Discover what’s new in the Cortex Innovation platform.
Summary
2022.9 is the first release of the next generation of Cortex and begins our journey to improve on the previous 7.X generation starting with the following areas:
This release introduces a new engine to execute automation solutions, and has shown significant performance improvements compared to 7.X, both in our own observations and customers installations. For example, one customer solution that has been migrated to 2022.9 has shown the time taken to run their tests reduce from 210 minutes to 10 minutes.
This release introduces the concept of Encryptable and Encrypted text, allowing for blocks to identify and interact with sensitive data that should/must be encrypted at rest and during data transfer.
Improved Observability
This release introduces:
Structured logging providing a defined JSON format for logs produced by the Innovation Platform
Dashboards providing observability of the Innovation Platform in Production; these use structured logs as their source
Other Improvements
This release introduces a number of other improvements, such as:
Versioned APIs which allow our APIs to evolve in future releases without breaking existing automation solutions
For a full list of what has been introduced in this release, please see the 2022.9 Release Notes
2 - Overview
Find out what the Cortex platform is, what it can do, and how you can get started?
What is Cortex?
Low-code automation
Cortex is a low-code, automation and orchestration platform, that enables organisations to graphically capture and automate anything from simple tasks, to interactive workflows, to complex IT and business processes that span the entire organisation.
Enterprise-grade
Evolved from process and control engineering for mission-critical environments, Cortex provides enterprise-grade functionality to cover the full automation lifecycle; enabling rapid delivery of automation on-premise or in the cloud, from inception to production, without the need for software development experience.
Built for everyone
Our vision is a world where everyone can automate, and Cortex is being built for everyone, not just software developers, with the goal of removing barriers to entry and putting your people at the heart of your automation.
Using Cortex, global organisations have been able to increase their capacity, velocity, quality, efficiency, agility and transform their business and IT operations in months.
Cortex has been deployed for a diverse set of use cases, including:
Lights out monitoring and management of fixed-line telephony networks
Data center provisioning
Patching of servers
IT service diagnostics
Swivel chair operations
Employee onboarding and offboarding
Animal welfare compliance checks
Resulting in successful outcomes
Cortex has resulted in many successful outcomes, including:
Increased revenue
Increased profit
Redeployment of skilled employees
Reduction in MTTR
Reduction in average handling time
Accelerate your digital transformation
Wherever you are on your automation journey and whatever you are trying to achieve, small or large, simple or complex, Cortex can help accelerate a successful transformation of your operations.
Let us help you to get started by participating in one of our enablement pathway programs:
1. Kickstarter - Free two/three day workshop that enables the rapid configuration of a cloud-based Cortex platform to prototype, and demonstrate automation in context.
2. Design Sprint - A two week formalised approach to automation based on our 300+ man years of knowledge and experience. Facilitated by Cortex, the Automation Design Sprint works through the required stages of automation, from vision and objectives to prototype and feedback.
3. Launch Program - A twelve week program which takes your team through the phases of mobilisation, design of automation, trial testing and sign-off to production.
4. Acceleration Program - A three, six or nine month program that delivers the framework for organisations to effectively and efficiently accelerate their team in the design, development, and delivery of automation using the Cortex platform.
3 - Getting Started
Get up and running with the Cortex Innovation platform in minutes.
3.1 - Install On-Premise
Information about installing Cortex Innovation to virtual machines or physical servers on-premise.
Cortex Innovation can be deployed on-premise on its own or added to an existing 7.2 installation.
3.1.1 - Install Innovation Only
Information about installing a Cortex Innovation platform.
Cortex Innovation can be deployed on-premise across multiple servers to provide improved scale and high availability (HA), or to a single server if scale and HA aren’t required.
3.1.1.1 - Multiple Server - With HA (Recommended)
Information about installing Cortex Innovation across multiple on-premise servers with high availability (HA), including: information about components, supported architectures, prerequisites and installation instructions.
Multiple server installations with HA are recommended for the following scenarios:
Production installations that are required to scale and support HA
3.1.1.1.1 - Architecture
Information about the recommended Innovation platform architecture, including component descriptions.
Web portal that hosts applications for creating automation solutions and managing their full life-cycle, including design, development, testing, deployment, monitoring, maintenance and ultimately end-of-life.
Application hosted in Cortex Gateway that provides the graphical, low-code environment for developing, testing, versioning, publishing and managing the full life-cycle of automation solutions.
Required
Web Application Server
Cortex Flow Debugger Service
Web application that allows flows to be debugged and executed. Used by Cortex Studio to debug flows and provide block information.
Required
Web Application Server
Cortex API Gateway Service
Application Service that routes client requests to the correct distributed Cortex services.
Required
Application Server
Cortex Flow Execution Service
Application Service that executes automation flows.
Required
Application Server
Cortex Block Packages
A set of files which contain the blocks that users can use to build flows. Used by the Cortex Flow Debugger Service and the Cortex Flow Execution Service.
Required
Web Application Server, Application Server
Cortex Gateway Databases
A set of databases created automatically by Gateway which are used for storing data related to user roles, flows, etc. Hopefully, we can remove the need for Gateway Databases in the next release.
Distributed systems platform that hosts the Cortex services where automation solutions are deployed to; provides scalable, reliable and manageable enterprise-grade High Availability (HA) using clustering.
Message broker used by the NServiceBus messaging platform to transport messages asynchronously between distributed Cortex services using publish/subscribe mechanism.
Information about the prerequisites required on each server type for installation.
Prerequisites
The prerequisites required for each server role (as described in Architecture) are laid out in this guide. These must be considered before undertaking installation.
Hardware Requirements
Note
The recommended number of servers is 5, and allows each server role instance to be installed on its own server.
All servers must be on the same domain and cannot be domain controllers.
DNS Requirements
The installation requires IP to hostname resolution to be available. Please ensure that you have the appropriate pointer (PTR) records configured on the DNS server for all of your servers (Web, Application and Load Balancer).
Licensing Requirements
A valid Cortex licence file and Cortex Innovation feature identifier must be procured from Cortex. The feature identifier is a GUID which will be used when configuring the Gateway installation. The licence file is needed when installing the Web Application server and it should contain fingerprints for the Web Application Server and each Application Server.
To get a licence file and feature identifier take the following steps:
Copy the following template to a text file:
Web Application Server
MachineID:
Fingerprint:
Application Server 1
MachineID:
Fingerprint:
Application Server 2
MachineID:
Fingerprint:
Application Server 3
MachineID:
Fingerprint:
Please also include a suitable Cortex Innovation feature identifier.
From that folder, copy Cortex.Licensing.FingerprintGeneration.exe to the Web Application server.
Double-click Cortex.Licensing.FingerprintGeneration.exe to run it. A command line window will appear, containing a machine identifier and fingerprint, e.g:
Copy the output (machine identifier and fingerprint) to the Web Application Server section of the text file created in the initial step. Note that the machine identifier can be changed to any string, provided that it is different for each server.
For each Application Server take the following steps:
Copy Cortex.Licensing.FingerprintGeneration.exe to the Application server.
Double-click Cortex.Licensing.FingerprintGeneration.exe to run it. A command line window will appear, containing a machine identifier and fingerprint, e.g:
Copy the output (machine identifier and fingerprint) to one of the Application Server sections of the text file created in the initial step. Note that the machine identifier can be changed to any string, provided that it is different for each server.
Request a licence and feature identifier by raising a case in the Cortex Service Portal, including the contents of the text file containing all of the fingerprint and machine information in the body of the case.
When the licence and feature identifier have arrived, copy the file Cortex.lic to %ProgramData%\Cortex\Licences on the Web Application Server, creating the Cortex and Licences folders if they don’t exist. Save the feature identifier for use when Installing Gateway.
Web Browser Requirements
Gateway supports the latest versions of the following browsers:
Chrome
Edge
Firefox
Additional Load Balancer Server Requirements
Filesystem Requirements
If using the included gobetween load balancer, Network Discovery and File Sharing must be enabled on the Load Balancer Server:
Open File Explorer.
Click Network on the left.
A banner similar to the following will appear if Network Discovery and File Sharing is turned off:
Network and File Discovery Disabled
Click the banner.
Click Turn on network discovery and file sharing:
Enable Network and File Discovery
Alternative Load Balancer Requirements
Innovation has a gobetween load balancer included that isn’t highly available; It is possible to use an alternative. The requirements for installing an alternative load balancer are as follows:
Must support a round robin (or similar) method of load balancing to specified ports on 3 nodes.
Must be able to health check each node by running a predefined batch script (ApiGatewayTypeHealthcheck.bat, which resides in the gobetween folder of the Cortex Innovation 2022.9 - App Server Install Scripts) that returns 1 for healthy and 0 for unhealthy.
Must be able to access each of the Application Servers via HTTPS.
Ideally it should be highly available to avoid a single point of failure in the system.
Additional Application Server Requirements
Filesystem Requirements
All Application Servers must use an NTFS filesystem.
Network Discovery and File Sharing should be enabled on each Application Server:
Open File Explorer.
Click Network on the left.
A banner similar to the following will appear if Network Discovery and File Sharing is turned off:
Network and File Discovery Disabled
Click the banner.
Click Turn on network discovery and file sharing:
Enable Network and File Discovery
Service Requirements
The following Windows Services must be running on all Application Servers:
Remote Registry
Windows Event Log
Performance Logs & Alerts
Security Requirements
Installation User
A domain user which is a member of the Local Administrators group on all Application Servers and Load Balancer Server must be available to run the installation scripts. This is a prerequisite of Microsoft Service Fabric, which is the HA platform that Cortex Innovation is built upon.
Antivirus Exclusions
It is advised (by Microsoft Service Fabric) that the following antivirus exclusions are created on each Application Server to reduce antivirus processing on Service Fabric artefacts:
Folder Exclusions:
%ProgramFiles%\Microsoft Service Fabric
%ProgramData%\SF
%ProgramData%\SF\Logs
Process Exclusions:
Fabric.exe
FabricHost.exe
FabricInstallerService.exe
FabricSetup.exe
FabricDeployer.exe
ImageBuilder.exe
FabricGateway.exe
FabricDCA.exe
FabricFAS.exe
FabricUOS.exe
FabricRM.exe
FileStoreService.exe
A script is provided during installation to add these exclusions for Windows Defender. If any other antivirus software is running, these will need to be added manually.
If adding the exclusions manually, the Process Exclusions should be done before installation occurs, as the processes will be used during installation of the application and antivirus software can cause the installation to fail or timeout. Folder Exclusions may need to be added after installation has occurred as some antivirus software needs the folders to exist.
Port Requirements
Cortex Innovation and Microsoft Service Fabric require a range of firewall ports to be opened between the servers and specific services.
If you are using Windows Firewall, some ports are opened during installation and others are opened dynamically as needed. If any other firewall is used, it will be necessary to add the rules described in Port Requirements to open the correct ports.
The Cortex.Innovation.Test.PortUsage.ps1 script is provided during installation to test the ports on each Application Server and make sure they do not overlap with any other programs; most ports may be altered if this is the case, the description will say if this is not possible.
Certificate Requirements
Note
For production systems it is recommended that X.509 SSL wildcard certificates are obtained from a Certificate Authority and used for installation. For non-production systems, certificates can be omitted from installation and it will create and use self-signed certificates. This may prevent 3rd parties that require valid certificate verification to access the API Gateway Service.
An X.509 SSL wildcard certificate should be used to:
Secure communication between the load balancer and the nodes on the Application Servers.
Secure communication between the Application Services.
Allow Application Services to identify themselves to clients such as Gateway.
Prevent unauthorised nodes from joining the HA cluster.
Connect to Service Fabric Explorer from each of the Application Servers.
The certificate can be obtained from a Certificate Authority, such as Let’s Encrypt, and must meet the following requirements:
Subject field must be in a wildcard format, pertaining to the domain of the Application Servers (e.g. CN=*.domain.com).
Subject alternative names must include any additional host names that should be able to be used to access the API Gateway Service.
Certificate file must be in a .PFX file format, with a known password.
Certificate file must contain the full chain of certificates.
Certificate file must include the private key.
Key Usage extension must have a value of Digital Signature, Key Encipherment (a0).
Enhanced Key Usage must include Server Authentication and Client Authentication.
This file should be placed in a known location on the Application Server where the installation scripts will be run. This location will be required when running the installation script.
If required, a separate X.509 SSL certificate can be obtained to be used by the load balancer to communicate with the Application Services. It must meet all of the other requirements laid out above, except the subject field can also be the FQDN of the load balancer (e.g. CN=machine-name.domain.com).
Warning
It is critical to set a reminder to update certificates in good time before they expire. If they expire then the platform will cease to function and Cortex Service Portal must be contacted for support.
TLS Requirements
There is a set of non-compulsory security measures, recommended to be applied to the Application Servers, in order to prevent potential attacks that exploit known industry security vulnerabilities. This includes disabling all versions of SSL and TLS apart from TLS 1.2. And disabling all cipher suites apart from the following:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
See SSL Best Practices for a full list of the security changes which will be applied. The Cortex.Innovation.Install.Multiple.SSLBestPractices.ps1 script is provided during installation to apply these security changes to the Application Servers.
Additional Web Application Server Requirements
Security Requirements
Installation User
Domain users must be available to run the Application Pools for Gateway and Flow Debugger Service. These users must be given Log on as a service and Log on as a batch job permissions otherwise the Application Pools will not be able to run. Information about how to do this will be given during installation.
For Flow Debugger Service, the NETWORK SERVICE user can also be used.
Domain Requirements
For Gateway, only Windows domains with an Active Directory domain controller running Active Directory Domain Services are supported.
Supported versions of Active Directory are listed below:
Version
Verified?
Supported From
Supported Until
Windows Server 2003
✓
Cortex v2022.9
To be evaluated
Windows Server 2003 R2
Cortex v2022.9
To be evaluated
Windows Server 2008
Cortex v2022.9
To be evaluated
Windows Server 2008 R2
✓
Cortex v2022.9
To be evaluated
Windows Server 2012
Cortex v2022.9
To be evaluated
Windows Server 2012 R2
✓
Cortex v2022.9
To be evaluated
Windows Server 2016
✓
Cortex v2022.9
To be evaluated
Windows Server 2019
Cortex v2022.9
To be evaluated
Windows Server 2022
Cortex v2022.9
To be evaluated
Certificate Requirements
Both Gateway and the Flow Debugger Service require an X.509 SSL certificate to be installed on the Web Application Server. The certificate must have the following properties:
Enhanced Key Usage: Server Authentication and Client Authentication
Subject Alternative Names (SAN): At minimum the FQDN of the Server. It can also include NetBIOS Name, IP address, localhost, 127.0.0.1
If the user tries to navigate to an address not in the SAN list, then they will receive a certificate error.
Wildcard certificates and self-signed certificates can also be used. However, self-signed certificates are not recommended for production instances. Details on how to create a self-signed certificate can be found at Create Self-Signed Certificates.
The certificate may be the same one used for the Application Server installation.
More information about importing the certificate is given during installation.
TLS Requirements
There is a set of non-compulsory security measures, recommended to be applied to the Web Application Server, in order to prevent potential attacks that exploit known industry security vulnerabilities. This includes disabling all versions of SSL and TLS apart from TLS 1.2. And disabling all cipher suites apart from the following:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
See SSL Best Practices for a full list of the security changes which will be applied. The Cortex.Innovation.Install.SSLBestPractices.ps1 script is provided during installation to apply these security changes to the Web Application Server.
A software-based load balancer called gobetween is provided with the platform. This must be installed on its own server as it doesn’t support routing traffic to itself. It also doesn’t currently support HA, but it may be possible to use multiple gobetween load balancers with Anycast network addressing and routing to provide high availability, as described in https://en.wikipedia.org/wiki/Anycast; however, this has not been verified yet. It is possible to use an alternative load balancer to the one provided. ↩︎
Application Servers support HA via clustering. A cluster must consist of a minimum of 3 nodes, and the number of nodes must be an odd number to ensure a quorum. Currently only the Bronze availability (3 nodes) is supported. Silver, Gold and Platinum support will be added in future. ↩︎
Windows Server Standard and Datacenter editions are supported. Filesystem must be NTFS and networking must use IPv4. Linux is not supported, but may be in the future. ↩︎
SQL Server Express, Standard and Enterprise are supported. Other databases are not supported. Note that Transparent Data Encryption is not supported on SQL Server Express. ↩︎
PowerShell 5.1 ships with Windows Server 2016 and 2019. ↩︎
IIS is supported; other web servers, including IIS Express are not supported. ↩︎
Ships as a windows role within Windows Server 2019. ↩︎
Ships as a windows role within Windows Server 2016. ↩︎
3.1.1.1.3 - Install Application Servers and Load Balancer
Information about installing the Application Servers and Load Balancer Server.
Install Application Servers and Load Balancer
This guide describes how to install the Application Servers and Load Balancer Server. Please ensure that the Prerequisites for installing Innovation have been read before starting this installation.
Make Installation Artefacts Available
Choose one of the Application Servers to be used for installation, and copy the following artefacts to a folder on it (the version numbers may differ):
Cortex Innovation 2022.9 - Block Packages.zip
Cortex Innovation 2022.9 - App Services.zip
Cortex Innovation 2022.9 - App Server Install Scripts.zip
Extract the Cortex Innovation 2022.9 - App Server Install Scripts.zip file to a folder with the same name.
Install Microsoft .NET Framework 4.7.1
Microsoft Service Fabric requires a minimum of Microsoft .NET Framework 4.7.1 to be installed on each Application Server.
To find the version of the framework that is installed:
On the Start menu, choose Run.
In the open box, enter regedit.exe. You must have administrative credentials to run regedit.exe.
In the Registry Editor, open the subkey HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full.
If the Full subkey is not present, then you do not have the .NET Framework 4.5 or later installed.
Check for a DWORD value named Release. The existence of the Release DWORD indicates the .NET Framework 4.5 or newer has been installed on that computer. If the value is 461308 or over then at least .NET Framework 4.7.1 is installed and no further steps need to be taken. If it is not installed, continue with the following steps to install it.
These are non-compulsory security measures, recommended to be applied to Application Servers and the Load Balancer Server, in order to prevent potential attacks that exploit known industry security vulnerabilities.
Applying these measures may impact other applications running on your servers. Therefore, it is your responsibility to ensure that other applications and their clients will not be affected by the changes.
Only Use Recommended Encryption Algorithms and TLS Protocols
A collection of registry settings need to be applied to guarantee your server is only using the recommended encryption algorithms and TLS protocols. Information about these settings can be found at SSL Best Practices.
Warning
Disabling specific TLS versions or specific Cipher Suites can have impact on Cortex components themselves as well as their communication capabilities with third party systems and services, e.g. Flow Debugger Service executing flows with blocks which communicate with 3rd parties via PowerShell or REST. All parties communicating together must support a shared protocol version and cipher suite, otherwise they will not be able to establish a secure communication link between each other.
The settings can be applied by running a script. Be aware that each server will be restarted when the script is run. Apply the settings by following these instructions:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Install.Multiple.SSLBestPractices.ps1 script using the following command, modifying the ApplicationServers value to contain the NETBIOS names or fully qualified domain names of the Application Servers and the LoadBalancerServer value to contain the NETBIOS names or fully qualified domain name of the Load Balancer Server (remove the LoadBalancerServer parameter if using an alternative load balancer):
To avoid answering all of the prompts -Override 0 can be added to the end of the script. This will automatically apply all settings and forcibly restart the servers.
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all servers (Application and Load Balancer) and press OK.
If -Override 0 has been specified no further steps need to be taken and you can move on to the next section when the servers have restarted.
To use all the recommended settings click Apply all to the each Apply Cortex recommended security best practices prompt.
To selectively apply each setting select Choose which to apply. Each change will then be prompted with a Yes/No confirmation before applying. This will need to be done for each server.
Restart each machine when the script asks. The current machine will be restarted last, the PowerShell script will close at this time.
Add Antivirus Exclusions
If Windows Defender is not running on the Application Servers, ensure that the Antivirus Exclusions have been added to the running antivirus software on each of the Application Servers and continue to the next section, otherwise follow these steps:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Add.WindowsDefenderExclusions.ps1 script using the following command, modifying the ApplicationServers value to contain the NETBIOS names or fully qualified domain names of the Application Servers:
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all Application Servers and press OK.
A message will indicate that the script has completed successfully.
Check Port Usage
To check all necessary ports are free, follow these steps.
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Test.PortUsage.ps1 script using the following command, modifying the ApplicationServers value to contain the NETBIOS names or fully qualified domain names of the Application Servers:
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all Application Servers and press OK.
If all ports are free, the script will report the following for each Application Server:
All ports required by Cortex Innovation are free
If this is the case, continue to the next section. Otherwise, consult the messages returned by the script, which will give details about how to modify the Cortex.Innovation.Install.Config.json configuration file, in the Cortex Innovation 2022.9 - App Server Install Scripts folder, to use different ports. This will be used later during installation.
The Cortex.Innovation.Test.PortUsage.ps1 script cannot currently re-check modified ports in the configuration file so these need to be manually checked to see that they are free.
Configure Installation Script
In the Cortex Innovation 2022.9 - App Server Install Scripts folder, locate the Cortex.Innovation.Install.ps1 script and open it with a text editor.
Choose the tab below that matches the configuration for this installation, then update the script to match, changing the parameters according to the details given below:
Configure this value with the location of the Application Services zip file on the Application Server used for installation.
BlockPackagesPath
Configure this value with the location of the Block Packages zip file on the Application Server used for installation.
ApiGatewayBasicAuthUserName
Configure this value with the username that will be used for Basic Authentication when making HTTPS requests to the API Gateway Service (e.g. starting production flows).
For security reasons it is recommended that the default value BasicAuthUser should be changed.
Currently only Basic Authentication using a single user is supported, OAuth2 will be supported in a future release.
Configure this value with the password that will be used for Basic Authentication when making HTTPS requests to the API Gateway Service (e.g. starting production flows).
This password should be Cortex Encrypted. For security reasons it is recommended that the default value ADA9883B11BD4CDC908B8131B57944A4 should be changed.
A name identifying the platform being installed. This must have no spaces or symbols. It will be appended to the node names that are displayed in Service Fabric Explorer.
ApplicationServerIPv4Addresses
The IPv4 addresses of the Application Servers. The first of these must be the Application Server used for installation.
LoadBalancerServerIPv4Address
The IPv4 address of the Load Balancer Server. This is only needed if using the built-in load balancer.
ServerCertificatePath
The local path of a .PFX certificate file on the first Application Server in the ApplicationServerIPv4Addresses list. Environment variables cannot be used.
This is only needed if installing with CA Certificates (Recommended). The certificate should meet the Certificate Requirements.
This certificate will be used for:
Securing communication between the Application Services.
Allowing Application Services to identify themselves to clients such as Gateway.
Preventing unauthorised nodes from joining the HA cluster.
Connecting to Service Fabric Explorer from each of the Application Servers.
Warning
It is critical to set a reminder to update certificates in good time before they expire. If they expire then the platform will cease to function and Cortex Service Portal must be contacted for support.
ServerCertificatePwd
The password for the .PFX certificate file specified in ServerCertificatePath.
This is only needed if installing with CA Certificates (Recommended).
ClientCertificatePath
The local path of a .PFX certificate file on the first Application Server in the ApplicationServerIPv4Addresses list. This can be the same certificate as the ServerCertificatePath. Environment variables cannot be used.
This is only needed if installing with CA Certificates (Recommended) and using the Built-In Load Balancer. The certificate should meet the Certificate Requirements.
This certificate will be used for:
Securing communication between the load balancer and the nodes on the Application Servers.
Warning
It is critical to set a reminder to update certificates in good time before they expire. If they expire then the platform will cease to function and Cortex Service Portal must be contacted for support.
ClientCertificatePwd
The password for the .PFX certificate file specified in ClientCertificatePath.
This is only needed if installing with CA Certificates (Recommended) and using the Built-In Load Balancer.
UseSelfSignedCertificates
Installs Application Services and required infrastructure using generated Self-Signed Certificates rather than CA Certificates.
Not recommended for production use.
SkipLoadBalancer
Installs Application Services and required infrastructure without installing a load balancer. Use when using an alternative load balancer or no load balancer.
Credential
The credentials of the user which will be used to perform remote operations on the Application Servers. It must be a domain user that is a member of the local Administrators group on all servers.
This does not need to be changed, a prompt will appear to enter this information when the script is run.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
More advanced configuration (such as changing ports) can be undertaken by modifying the Cortex.Innovation.Install.Config.json file but this shouldn’t be required for most installations. More information about this can be found at Advanced Application Server and Load Balancer Configuration Changes.
Save and close Cortex.Innovation.Install.ps1.
Test Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Type the following command into PowerShell:
.\Cortex.Innovation.Install.ps1-WhatIf
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to test the installation script.
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all servers (Application and Load Balancer) and press OK.
A password prompt will appear. Enter a password which will be used to create a user in RabbitMQ.
Wait for the command to finish. It will display the output of the installation command without making any changes to the system, to ensure things like communication between the servers are working.
Check that there have been no errors in the script; these would appear in red in the console.
If there are no errors, continue to the next section; otherwise, check if the errors have any instructions for rectifying the issue and follow them.
If there are no useful instructions, check that all previous steps have been followed correctly and, if not, rectify it and run the command again.
If this does not work, please contact Cortex Service Portal for further assistance. The WhatIf script will have created a temporary version of the config file in the script location, showing what changes would be made to it when the script runs. The name is appended with -WhatIf (e.g. Cortex.Innovation.Install.Config-WhatIf.json). This file can be provided when obtaining support.
Run Installation Script
Type the following command into PowerShell:
.\Cortex.Innovation.Install.ps1
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install HA Services and the required infrastructure.
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all servers (Application and Load Balancer) and press OK.
A password prompt will appear. Enter a password which will be used to create a user in RabbitMQ. This should be entered carefully and recorded as it may be needed if seeking support from Cortex Service Portal. Press OK.
Wait for the script to finish running. This should take approximately 10 minutes.
Check that there have been no errors in the script; these would appear in red in the console.
If there are any errors, then please follow any instructions given within them to rectify the situation, check your configuration files, and retry the installation.
In some circumstances, retrying may error due to components being installed already. In this case please run the following command, followed by the original installation command:
Import the client certificate, used in the ClientCertificatePath parameter of the Configure Installation Script section, to your Current User certificate store. This can be achieved by double clicking on the client certificate .PFX file and following the wizard.
If using self-signed certificates, the certificate can be retrieved by using the Manage Computer Certificates tool in Windows to export the CortexServerCertificate from the Personal store and then importing it to the Current User store by double-clicking on it and following the wizard.
Open a web browser.
Navigate to https://app-server.domain.com:9080/Explorer, where app-server.domain.com is the fully qualified domain name of any Application Server. Replace 9080 with new httpGatewayEndpointPort value if it was changed during configuration.
The screen should resemble that in the following figure:
Healthy Service Fabric Explorer Cluster
The status circles should be entirely green - this indicates that all nodes, services and instances are healthy. Other status pages can be accessed by expanding items in the leftmost pane. Issues can be tracked down to the failing component by expanding items with warning triangles or error icons on. The next few diagrams show the status pages for a healthy system.
After expanding the application, clicking on any of the services should display a green circle and Status = Active:
Healthy Service Fabric Explorer Service
After expanding either of the services, clicking on any of the instances/partitions should display a green circle and Status = Ready:
Healthy Service Fabric Explorer Instance
Clicking on any of the nodes at the bottom of the leftmost pane should display a green circle and Status = Up:
Healthy Service Fabric Explorer Node
If any warning triangles appear, wait for 5 minutes or so as the cluster may still be starting up. If the cluster looks OK, go to the next section.
If the warnings persist or anything on the screen goes red, expand the items to find the individual services and instances which have errors or warnings. Warnings should not be ignored as they can indicate that the service can’t start but is still in the retry phase. Error and warning messages should be displayed on the status screens and should indicate what is wrong.
If no useful message can be seen here, the service log files may contain more information. These can be found on each Application Server at:
%ProgramData%/Cortex/Cortex API Gateway Service
%ProgramData%/Cortex/Cortex Flow Execution Service
If no solution can be found, please contact Cortex Service Portal for further assistance.
Preserve installation files
Ensure that the installation files are backed up or kept on the server, especially the scripts and config files that have been modified. This will make it easier to perform further actions in future, such as troubleshooting, certificate rollover, uninstallation, reinstallation and updates.
Information about installing the Web Application Server.
Install the Web Application Server
This guide describes how to install the Web Application Server. Please ensure that Install Application Servers and Load Balancer has been completed before starting this installation.
Make Installation Artefacts Available
We recommend that the Flow Debugger Service and Gateway are installed on the same Web Application Server. Copy the following artefacts to a folder on the machine (the version numbers may differ):
Cortex Innovation 2022.9 - Web App Server Install Scripts.zip
Extract the Cortex Innovation 2022.9 - Web App Server Install Scripts.zip zip file to a folder with the same name.
Install Prerequisites
Licensing
Ensure that a valid Cortex licence file named Cortex.lic exists on the Web Application server, in the location %ProgramData%\Cortex\Licences. If it does not, follow the instructions located at Licensing Requirements.
Install SQL Server or SQL Express
Use one of the following installation guides to install SQL Server or SQL Server Express:
Gateway requires a minimum of Microsoft .NET Framework 4.7.1.
To find the version of the framework that is installed:
On the Start menu, choose Run.
In the open box, enter regedit.exe. You must have administrative credentials to run regedit.exe.
In the Registry Editor, open the subkey HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full.
If the Full subkey is not present, then you do not have the .NET Framework 4.5 or later installed.
Check for a DWORD value named Release. The existence of the Release DWORD indicates the .NET Framework 4.5 or newer has been installed on that computer. If the value is 461308 or over then at least .NET Framework 4.7.1 is installed and no further steps need to be taken. If it is not installed, continue with the following steps to install it.
Check if Web Deploy is already installed by going to Control Panel → Programs → Programs and Features; if Web Deploy is already installed, it will be listed as Microsoft Web Deploy.
If it is not installed, download Microsoft Web Deploy version 3.0 or later (WebDeploy_amd64_en-US.exe) to the server.
Double-click the downloaded file to start the installation.
Follow the installation wizard to install Web Deploy; on the Choose Setup Type page select Typical.
Install Visual C++ Redistributable
Check if Visual C++ 2013 Redistributable (x64) is already installed by going to Control Panel → Programs → Programs and Features; if Visual C++ Redistributable is already installed, it will be listed as Microsoft Visual C++ 2013 Redistributable (x64).
Double-click the downloaded file to start the installation.
Follow the installation wizard to install the Visual C++ Redistributable.
Install Certificate
Both Gateway and the Flow Debugger Service require an X.509 SSL certificate to be installed on the Web Application Server. The certificate must have the following properties:
Enhanced Key Usage: Server Authentication and Client Authentication
Subject Alternative Names (SAN): At minimum the FQDN of the Server. It can also include NetBIOS Name, IP address, localhost, 127.0.0.1
If the user tries to navigate to an address not in the SAN list, then they will receive a certificate error.
Wildcard certificates and self-signed certificates can also be used. However, self-signed certificates are not recommended for production instances. Details on how to create a self-signed certificate can be found at Create Self-Signed Certificates.
You can import the certificate by right clicking the certificate file, selecting Install Certificate and following the wizard. When prompted, ensure you import it into the Local Machine store and not Current User.
To verify the certificate is imported:
Click the Windows button (Start)
Type certlm.msc and press Enter to open the Certificate Manager dialog
Expand Personal and select Certificates
You should see your certificate in this store
Warning
It is critical to set a reminder to update certificates in good time before they expire. If they expire then the platform will cease to function and Cortex Service Portal must be contacted for support.
IIS Role Setup and Configuration
Install Internet Information Services (IIS)
Install the required features by following these instructions:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Web App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Web App Server Install Scripts"
Run the Cortex.Innovation.Install.WindowsFeatures.ps1 script using the following command, this may take a few minutes:
.\Cortex.Innovation.Install.WindowsFeatures.ps1
Check the output is as follows:
Web-WebSockets is installed
Web-Asp-Net45 is installed
Web-Net-Ext45 is installed
Web-ISAPI-Ext is installed
Web-ISAPI-Filter is installed
Net-Framework-45-Core is installed
Net-Framework-45-ASPNET is installed
Web-Default-Doc is installed
Web-Dir-Browsing is installed
Web-Http-Errors is installed
Web-Static-Content is installed
Web-Http-Logging is installed
Web-Http-Redirect is installed
Web-Request-Monitor is installed
Web-Stat-Compression is installed
Web-Dyn-Compression is installed
Web-Filtering is installed
Web-Windows-Auth is installed
Web-Mgmt-Console is installed
Web-Mgmt-Service is installed
Register and Allow .NET CLR v4.0.30319 with IIS
Note
Unless .NET CLR v4.0.30319 is registered and allowed with IIS, Gateway and Flow Debugger Service will not work.
Open a Windows PowerShell (x64) window as administrator.
Once PowerShell confirms that it has finished installing .NET CLR v4.0.30319, close the PowerShell window.
Install URL Rewrite Module
The URL Rewrite IIS Manager module is required to enable web applications on your server to rewrite URLs. This is needed to allow HTTP URLs to redirect to the equivalent HTTPS ones.
To install the URL Rewrite module take the following steps:
In the left-hand pane of Internet Information Service (IIS) Manager, select the server node.
Ensure that there is an icon with the title URL Rewrite under the IIS feature section:
Url Rewrite Module Icon
If there is an icon, URL Rewrite module is installed and no further steps are required.
If there is no icon, the module is not installed and the following steps must be taken:
After successfully installing, close and reopen IIS Manager. The URL Rewrite icon should now be visible.
Apply Recommended Security Measures
These are non-compulsory security measures, recommended to be applied to Web Application Servers, in order to prevent potential attacks that exploit known industry security vulnerabilities.
Applying these measures may impact other applications running on your server. Therefore, it is your responsibility to ensure that other applications and their clients will not be affected by the changes.
Only Use Recommended Encryption Algorithms and TLS Protocols
A collection of registry settings need to be applied to guarantee your server is only using the recommended encryption algorithms and TLS protocols. Information about these settings can be found at SSL Best Practices.
Warning
Disabling specific TLS versions or specific Cipher Suites can have impact on Cortex components themselves as well as their communication capabilities with third party systems and services, e.g. Flow Debugger Service executing flows with blocks which communicate with 3rd parties via PowerShell or REST. All parties communicating together must support a shared protocol version and cipher suite, otherwise they will not be able to establish a secure communication link between each other.
Apply the settings by following these instructions:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Web App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Web App Server Install Scripts"
Run the Cortex.Innovation.Install.SSLBestPractices.ps1 script using the following command:
.\Cortex.Innovation.Install.SSLBestPractices.ps1
Note
To avoid answering all of the prompts -Override 0 can be added to the end of the script. This will automatically apply all settings and forcibly restart the server.
If -Override 0 has been specified no further steps need to be taken and you can move on to the next section when the server has restarted.
To use all the recommended settings click Apply all to the first prompt.
To selectively apply each setting select Choose which to apply. Each change will then be prompted with a Yes/No confirmation before applying.
Restart the machine when the script asks.
Add HTTPS Firewall Rule
If any firewall is running on the Web Application Server, it must be configured to allow communication inbound via TCP on the port configured for HTTPS (usually 443). See Configure Firewalls for information about adding rules to Windows Firewall.
Create Web Site
Gateway and Flow Debugger Service can either be installed to an existing web site or a newly created web site. If you are installing into an existing web site skip to Configure Web Site.
The steps to create a new web site are:
In Windows File Explorer, navigate to the default IIS folder (usually %SystemDrive%\inetpub\wwwroot, e.g. C:\inetpub\wwwroot).
Ensure there is a folder called Cortex; if not create it.
In the left-hand pane of Internet Information Service (IIS) Manager, expand the server node.
Right-click the Sites node under the server and select Add Website….
Set the Site name to Cortex.
Set the Physical path to the folder created above (e.g. C:\inetpub\wwwroot\Cortex), by clicking on the ellipses …, selecting the appropriate directory and clicking OK.
Click OK. If an existing site is already using the specified port, a warning will be displayed. Either click No and change the Port in the Add Website dialog, or click Yes and stop the other website.
Configure Web Site
The web site which the Gateway and Flow Debugger Service are installed under requires additional configuration.
Configure HTTPS
Both the Gateway and Flow Debugger Service should be configured to use HTTPS:
Note
For sites using self-signed SSL certificates, the HTTPS URL redirection will only work in Google Chrome browsers. For all other supported browsers, an SSL certificate signed by a Certificate Authority must be used to enable HTTPS URL redirection.
In the left-hand pane of Internet Information Service (IIS) Manager, expand the server node.
Expand the Sites node under the server.
Right-click the web site where Gateway will be installed and select Edit Bindings….
Click Add…
Set Type to https.
Set the appropriate Port number (typically 443). The Host name box can be left blank.
Note
Configuring your system to use a port other than the HTTPS default of 443 is not compatible with HTTP Strict Transport Security (HSTS). If your configuration requires HTTPS to run on a port other than 443, the HSTS configuration must be turned off. This can be achieved by configuring the Add Strict-Transport-Security when HTTPS rewrite rule’s enabled setting to false in web.config after installation.
Select the SSL certificate that was installed in the Install Certificate section.
Click OK. If an existing site is already using the specified SSL port, a warning will be displayed. Either click No and change the Port in the Add Site Binding dialog, or click Yes and stop the other website.
It is recommended to remove the http site binding.
Install Flow Debugger Service
Get Application Pool User
A domain user account is required for the Flow Debugger Service web application pool and must be created prior to performing the installation. In line with best practices, this account should not be used for any purposes other than those specified for the Flow Debugger Service. Alternatively, the NETWORK SERVICE user may also be used.
This user must currently have access to the default NuGet directory, in order to load block packages correctly. To add permissions for the user take the following steps:
Navigate to %SystemRoot%\System32\config\systemprofile\AppData\Roaming\ and create a new folder named NuGet if one does not exist.
Right-click on the NuGet folder and click Properties.
In the dialog, click the Security tab.
Click the Edit... button.
Click the Add... button.
Enter the username of the application pool user and click OK.
In the Permissions section at the bottom, check Full control
Click OK.
The user must be given Log on as a service and Log on as a batch job permissions. To do this take the following steps:
Navigate to Start -> Administrative Tools -> Local Security Policy.
In the Local Security Policy dialog, expand the Local Policies node then select User Rights Assignment.
Take the following steps for the Log on as a service and Log on as a batch job policies:
In the right-hand panel, double-click on the policy.
In the Properties dialog, click on the Add User or Group button.
Note
It is possible to use the Advanced… button to look up names rather than entering them manually. Various filters can be set to find the correct user or group more easily. Multiple users can be selected by holding down CTRL while clicking. OK adds the selected users or groups into the Enter the object names to select text box.
Type the name of the application pool user account into the Enter the object names to select text box. Click the Check Names button to confirm that the user exists.
Click OK on the Select Users dialog, and then confirm the user is correct by clicking OK on the Properties dialog.
Configure Installation Script
In the Cortex Innovation 2022.9 - Web App Server Install Scripts folder, locate the Cortex.Innovation.Install.FlowDebuggerService.ps1 script and open it with a text editor.
Choose the tab below that matches the configuration for this installation, then update the script to match, changing the parameters according to the details given below:
Configure this value with the password that will be used for Basic Authentication when Gateway makes HTTPS requests to the Flow Debugger Service.
This password should be Cortex Encrypted. For security reasons it is recommended that the default value ADA9883B11BD4CDC908B8131B57944A4 should be changed.
Enables Flow Debugger Service to communicate with Gateway using generated Self-Signed Certificates rather than CA Certificates.
Not recommended for production use.
Credential
The credentials of the user that will be used to run the Debugger application pool in IIS.
This does not need to be changed, a prompt will appear to enter this information when the script is run.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
Save and close Cortex.Innovation.Install.FlowDebuggerService.ps1.
Run Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Web App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Web App Server Install Scripts"
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install the Flow Debugger Service.
A credentials prompt will appear. Enter the credentials of the user that should run the Debugger application pool in IIS. If using the NETWORK SERVICE user, enter any user as the username and leave the password blank; the NETWORK SERVICE user will need to be selected in the final step.
Wait for the script to finish running. This should take approximately 2 minutes.
An error may have appeared saying:
The Windows Process Activation Service service is not started.
This can be ignored.
Check that there have been no other errors in the script; these would appear in red in the console.
If there are any errors, then please follow any instructions given within them to rectify the situation, and retry the installation.
If the errors do not give any instructions on how to rectify, please contact Cortex Service Portal for further assistance.
If using NETWORK SERVICE for the application pool user:
Open Internet Information Services (IIS) Manager.
On the left, expand the server node.
Click Application Pools.
Right-click on the Debugger application pool and select Advanced Settings....
In the Advanced Settings dialog, click on Identity and then click the ellipses (...).
In the Application Pool Identity dialog, select Built-in account, then select NetworkService from the drop-down, then click OK.
Right-click on the Debugger application pool and click Recycle....
Install Gateway
Get Application Pool User
A domain user account is required for the Gateway web application pool and must be created prior to performing the installation
below.
This user account is required to enable Gateway to access the Cortex database, with the following roles:
dbcreator
public
To add roles to database users take the following steps:
Open SQL Server Management Studio on the Web Application Server and log in.
Expand the server node, then Security then Logins.
If the user that will run the Gateway application pool is not in the list of logins, take the following steps, otherwise skip to step 4:
Right-click the Logins node and click New Login....
Enter the application pool user in the Login name box.
On the left pane, click Server Roles.
Check public and dbcreator
Click OK.
If the user that will run the Gateway application pool is in the list of logins, take the following steps:
Right-click on the application pool user.
Click Properties.
On the left pane, click Server Roles.
Check public and dbcreator.
Click OK.
In line with best practices, this account should not be given administrator rights, nor should it be used for any purposes other than those specified for Gateway.
The user must be given Log on as a service and Log on as a batch job permissions. To do this take the following steps:
Navigate to Start -> Administrative Tools -> Local Security Policy.
In the Local Security Policy dialog, expand the Local Policies node then select User Rights Assignment.
Take the following steps for the Log on as a service and Log on as a batch job policies:
In the right-hand panel, double-click on the policy.
In the Properties dialog, click on the Add User or Group button.
Note
It is possible to use the Advanced… button to look up names rather than entering them manually. Various filters can be set to find the correct user or group more easily. Multiple users can be selected by holding down CTRL while clicking. OK adds the selected users or groups into the Enter the object names to select text box.
Type the name of the application pool user account into the Enter the object names to select text box. Click the Check Names button to confirm that the user exists.
Click OK on the Select Users dialog, and then confirm the user is correct by clicking OK on the Properties dialog.
Create Gateway Application Pool
Open Internet Information Services (IIS) Manager.
Select and right-click the Application Pools node under the server and select Add Application Pool…
Set Name to Cortex Gateway.
Ensure that the .NET CLR version is set to .NET CLR Version v4.0.30319 (This may be configured by default).
Ensure that the Managed pipeline mode is set to Integrated (This may be configured by default).
Click OK
Right click on the created application pool and select Advanced Settings…
Click the ... next to Identity (under Process Model) to open a dialog, then select Custom Account and Set....
Click OK to close the Application Pool Identity dialog.
Click OK to close the Advanced Settings dialog.
Create New Web Application
In the left-hand pane of Internet Information Service (IIS) Manager, expand the server node.
Right-click on the site the application should be installed under and select Add Application…
Set the Alias to gateway. This must be lowercase.
Click Select… and from the Application pool dropdown select the Cortex Gateway application pool and click OK.
Set the Physical path to C:\inetpub\wwwroot\Cortex\Gateway by clicking on the ellipses … and selecting the appropriate directory. Create the C:\inetpub\wwwroot\Cortex\Gateway directory if it does not already exist.
Click OK.
Configure IIS Site Redirect to the Specified Web Application (Optional)
If the site hosting the Gateway web application is a newly created Cortex site or an existing site that doesn’t have its own content, it is recommended to redirect the site URL to the gateway web application URL, e.g. https://FullyQualifiedDomainName to https://FullyQualifiedDomainName/gateway.
Open Internet Information Services (IIS) Manager.
Select the site hosting the gateway web application and from IIS settings double-click the HTTP Redirect icon.
Click the check box Redirect requests to this destination.
Enter https://FullyQualifiedDomainName/gateway, replacing FullyQualifiedDomainName with the FQDN of the server.
In the Redirect Behaviour section, click Only redirect requests to content in this directory (not subdirectories).
In Actions click the Apply button.
Configure Installation Script
In the Cortex Innovation 2022.9 - Web App Server Install Scripts folder, locate the Cortex.Innovation.Install.Gateway.ps1 script and open it with a text editor.
Configure the script according to the details given below:
Configure this value with the location of the Cortex Innovation 2022.9 - Gateway.zip file on the installation server.
GatewayApplicationIISPath
Change to the correct Site Name/Application if either was modified from the defaults (Cortex/gateway) when creating the website or application.
ModelDBContextConnectionString
If SQL Server was installed as the default instance, change the Data Sourcein the connection string to localhost or, if it was installed on another machine, change it to the machine name.
If SQL Server was installed as a named instance, change it to .\{instanceName} replacing {instanceName} with the name of the instance or, if SQL Server was installed on a different machine, change it to {machineName}\{instanceName} replacing {machineName} with the machine name and {instanceName} with the name of the instance.
This will set the ModelDBContextConnectionString value in the Gateway web.config.
AuthContextConnectionString
If SQL Server was installed as the default instance, change the Data Sourcein the connection string to localhost or, if it was installed on another machine, change it to the machine name.
If SQL Server was installed as a named instance, change it to .\{instanceName} replacing {instanceName} with the name of the instance or, if SQL Server was installed on a different machine, change it to {machineName}\{instanceName} replacing {machineName} with the machine name and {instanceName} with the name of the instance.
This will set the AuthContextConnectionString value in the Gateway web.config.
SignalRContextConnectionString
If SQL Server was installed as the default instance, change the Data Sourcein the connection string to localhost or, if it was installed on another machine, change it to the machine name.
If SQL Server was installed as a named instance, change it to .\{instanceName} replacing {instanceName} with the name of the instance or, if SQL Server was installed on a different machine, change it to {machineName}\{instanceName} replacing {machineName} with the machine name and {instanceName} with the name of the instance.
This will set the SignalRContextConnectionString value in the Gateway web.config.
FeatureFlags
Replace InnovationId with the Cortex Innovation feature identifier, which should have been provided by Cortex when fulfilling the Licensing Requirements, if it wasn’t it should be requested using Cortex Service Portal.
This will set the FeatureFlags value in the Gateway web.config.
ServiceFabricApiGatewayEndpoint
Replace server.domain.com with the fully qualified domain name of the Load Balancer Server. The port should be specified if it is not the default HTTPS port (443), and there must be a trailing slash, e.g. https://server.domain.com/ or https://server.domain.com:8722/.
This will set the ServiceFabricApiGatewayEndpoint value in the Gateway web.config.
ServiceFabricUsingSelfSignedCertificates
Configure the value as $false if you used valid CA certificates when installing the Application Servers, $true if you used self-signed certificates.
This will set the ServiceFabricUsingSelfSignedCertificates value in the Gateway web.config.
ServiceFabricApiGatewayBasicAuthUsername
This must be changed if you used a non-default ApiGatewayBasicAuthUserName when installing the Application Servers; if so, this value must be configured to the one used.
This will set the ServiceFabricApiGatewayBasicAuthUsername value in the Gateway web.config.
This will set the ServiceFabricApiGatewayBasicAuthPassword value in the Gateway web.config.
DotNetFlowDebuggerEndpoint
Replace server.domain.com with the fully qualified domain name of the Web Application Server.
This will set the DotNetFlowDebuggerEndpoint value in the Gateway web.config.
DotNetFlowDebuggerBasicAuthUsername
This must be changed if you used a non-default FlowDebuggerBasicAuthUserName when installing the Flow Debugger Service; if so, this value must be configured to the one used.
This will set the DotNetFlowDebuggerBasicAuthUsername value in the Gateway web.config.
This will set the DotNetFlowDebuggerBasicAuthPassword value in the Gateway web.config.
DotNetFlowDebuggerUsingSelfSignedCertificates
Configure the value as $false if you are using valid CA certificates to secure the site containing Gateway and Flow Debugger Service, $true if using self-signed certificates.
This will set the DotNetFlowDebuggerUsingSelfSignedCertificates value in the Gateway web.config.
Test
This does not need to be changed, it will be set at a later stage.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
Save and close Cortex.Innovation.Install.Gateway.ps1.
Test Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Web App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Web App Server Install Scripts"
Type the following command into PowerShell:
.\Cortex.Innovation.Install.Gateway.ps1-Test
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to test the configuration.
In the event of any errors, there will be an error message displayed at the end of the output with a line confirming the Error Count.
Run Installation Script
Ensure the Gateway application pool is stopped:
Open Internet Information Service (IIS) Manager.
In the left pane, expand the server node.
Click Application Pools to display a list of the Application Pools.
Right-click the Cortex Gateway application pool and select Stop.
Note
Failure to stop the application pool will result in a permissions error when installing Gateway.
Type the following command into PowerShell:
.\Cortex.Innovation.Install.Gateway.ps1
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install Gateway.
In the event of any errors, there will be an error message displayed at the end of the output with a line confirming the Error Count.
Click OK, then wait for Windows Security to update the security information to the folder.
Click OK.
Start the Gateway application pool:
Open Internet Information Service (IIS) Manager.
In the left pane, expand the server node.
Click Application Pools to display a list of the Application Pools.
Right-click the Cortex Gateway application pool and select Start.
Once the application pool has been started, the site will be available on <protocol>://<host>:<port>/<webapplicationname>, e.g. https://localhost/gateway.
Note
If the application pool does not stay started, ensure that the user it runs as has Log on as a service and Log on as a batch job permissions or belongs to a group that has those permissions.
Preserve installation files
Ensure that the installation files are backed up or kept on the server, especially the scripts and config files that have been modified. This will make it easier to perform further actions in future, such as troubleshooting, certificate rollover, uninstallation, reinstallation and updates.
Follow the steps in the setup wizard to configure the relevant areas:
Account Details
Click Next Step:
Initial Setup Screen
Enter an email address for the Administrator and click Next Step:
Administrator Details Screen
Change the Administrator password to a unique, secret password and click Next Step:
Change Password Screen
LDAP Connection
Enter the details of your Active Directory server and provide a Username and Password for a user with read access to it:
A connection to an Active Directory server must be established in order to assign authorisation rights to users.
In the Server field, enter the Hostname, FQDN or IP Address of the Active Directory server that Gateway should use to authenticate and authorise users.
In the Port field, enter the port number of the Active Directory server. The well-known port for LDAP traffic is 389; if SSL encryption is used, the well-known port is 636.
If an SSL connection is to be used, tick the box Use SSL.
In the Username field, enter a valid username of a user that has read permissions for the Active Directory server.
In the Password field, enter the password of the user entered in the previous step.
To reduce the scope of any Active Directory searches, add one or more base DNs (Distinguished Names). For each base DN click Add and enter the full LDAP path e.g CN=group, OU=organisational unit, DC=domain, DC=com. These will be used as the roots of any Active Directory searches performed. For more information about distinguished names see https://msdn.microsoft.com/en-us/library/aa366101(v=vs.85).aspx.
Click Test Connection to validate the connection and the user credentials entered and click Next Step.
LDAP Connection Screen
LDAP Authorisation
If the authorisation grid fails to load first time round, click Retry.
Assign access permissions to Active Directory groups:
To allow users to access the various roles within Gateway, it is first necessary to assign them the appropriate access rights.
Gateway currently supports four roles, but only two are relevant for Cortex Innovation:
Admin
Studio
To give a user access to a role, set access for a group or Organisational Unit (OU) that the user is a member of:
Expand the groups or OUs, or search for the group or OU, to be assigned one or more roles.
Check the relevant roles for each group. Checking a parent group will cascade the setting to all child groups.
LDAP Authorisation Screen
Click Complete Setup to commit the changes.
To test the permissions, log out as Administrator and then log in as a user with Studio permissions.
Configure the Gateway Databases to use Transparent Data Encryption
Note
Transparent Data Encryption cannot be applied to SQL Server Express, only full SQL Server instances.
Once Gateway has been configured, if you wish to encrypt the databases using Transparent Data Encryption for improved security, this should now be performed by following the steps in Configuring TDE.
Information about trying out Cortex Innovation for the first time.
Try it out
This guide describes how to try out a new Innovation installation to make sure it is working. Please ensure that Setup Gateway has been completed before taking these steps.
Test Debugging Flows
Test the platform by creating a new flow and executing it using the following steps:
Click on the Flows charm, then the + button and click Group to open a dialog.
Enter a name for the group, configure the Permission Groups and click OK to create the group.
Click on the group to open it (refresh the page if it does not appear).
Inside the group, click the + button again and click on Flow to open a dialog. If the menu item is not present, it means that the FeatureFlags in the CortexGateway.SetParameters.xml file was not set properly when installing Gateway. See Troubleshooting for more information.
Enter a name for the flow, configure the Permission Groups and click OK to create the flow.
The flow should be displayed with a start flow block and end flow block. A list of block palettes should be displayed down the left hand side:
New Flow - Number of palettes may differ
If the blocks in the flow do not display or the palettes are not visible, see Troubleshooting for more information.
Add a Set Variable block and connect it between the start and end blocks.
Click the Set Variable block to open the Property Editor.
Set the Value property to the expression DateTimeOffset.Now.
Type Result into the Variable property and click Create Result.
In the Variable Editor, set Is Output Variable? to true for the new Result variable.
Set a breakpoint on the end block and start the flow. An execution token should appear, the Result variable should show the current time. If the token does not appear, try refreshing the page.
Continue or stop the execution.
Commit the flow.
Test Publishing Production Flows
Log in to Gateway with a user that has the Admin role.
Click on the Settings charm, then Packages.
Click Add Package Definition. Enter a package name and select the new flow to add to the package. Click Save to save the new package.
Click Publish. A success message should appear. If it doesn’t it means that either one or more of the parameters prefixed with Service Fabric in the CortexGateway.SetParameters.xml file was not set properly when installing Gateway, or the Application Services aren’t healthy. See Troubleshooting for more information.
Test Executing Production Flows
Open an HTTP client, such as Postman. Make a request with the following format:
Property
Value
Action
POST
URL
https://{FQDN of Load Balancer Server}/api/default/default/flows/{Flow Name}/executions?packageName={Package Name} e.g. https://load-balancer.domain.com/api/default/default/flows/NewFlow/executions?packageName=NewPackage
Content Type
application/json
Body
{}
Authentication
Basic
Username
The value used for ApiGatewayBasicAuthUserName when installing Application Services
Password
The value used for ApiGatewayBasicAuthPwd when installing Application Services (Unencrypted)
Note
If you used self-signed certificates when installing the Application Servers you will need to disable SSL certificate validation in your HTTP client.
The request should return a JSON object with the output variables of the flow e.g. { "Output": "2022-03-09T07:35:16+0000" }.
Cortex Innovation has now been verified and is ready to use.
3.1.1.2 - Single Server - Without HA
Information about installing Cortex Innovation on a single on-premise server without high availability (HA), including: information about components, supported architectures, prerequisites and installation instructions.
Single server installations with HA are not recommended for the following scenarios:
Production installations that are required to scale and support HA
3.1.1.2.1 - Architecture
Information about the recommended Innovation platform architecture, including component descriptions.
Web portal that hosts applications for creating automation solutions and managing their full life-cycle, including design, development, testing, deployment, monitoring, maintenance and ultimately end-of-life.
Application hosted in Cortex Gateway that provides the graphical, low-code environment for developing, testing, versioning, publishing and managing the full life-cycle of automation solutions.
Required
Web Application Server
Cortex Flow Debugger Service
Web application that allows flows to be debugged and executed. Used by Cortex Studio to debug flows and provide block information.
Required
Web Application Server
Cortex API Gateway Service
Application Service that routes client requests to the correct Application Services.
Required
Application Server
Cortex Flow Execution Service
Application Service that executes automation flows.
Required
Application Server
Cortex Block Packages
A set of files which contain the blocks that users can use to build flows. Used by the Cortex Flow Debugger Service and the Cortex Flow Execution Service.
Required
Web Application Server, Application Server
Cortex Gateway Databases
A set of databases created automatically by Gateway which are used for storing data related to user roles, flows, etc. Hopefully, we can remove the need for Gateway Databases in the next release.
Message broker used by the NServiceBus messaging platform to transport messages asynchronously between Application Services using publish/subscribe mechanism.
Erlang run-time required by the RabbitMQ message broker.
Required
Application Server
Single Server Architecture
The following architecture requires 1 server:
1 Server Architecture Diagram
Warning
This architecture is not recommended for production platforms that are required to scale and support HA. Additionally, upgrades require application redeployment with downtime rather than using rolling upgrades.
Information about the prerequisites required on each server type for installation.
Prerequisites
The prerequisites required for a single server (as described in Architecture) are laid out in this guide. These must be considered before undertaking installation.
Hardware Requirements
Note
This configuration is not recommended for production servers that are required to scale and support HA.
Server Role
Servers Required
CPU Cores (> 2GHz)
RAM (GB)
Disk (GB)
Single Server Application Server + Web Application Server
1
4+ Recommended 2 Minimum
16+ Recommended 12 Minimum
150+ Recommended 100 Minimum 30+ free on installation drive 40+ free on %ProgramData% drive
The server must be on a domain and cannot be a domain controller.
DNS Requirements
The installation requires IP to hostname resolution to be available. Please ensure that you have the appropriate pointer (PTR) records configured on the DNS server for the server.
Licensing Requirements
A valid Cortex licence file and Cortex Innovation feature identifier must be procured from Cortex. The feature identifier is a GUID which will be used when configuring the Gateway installation. The licence file is needed when installing the server and it should contain that server’s fingerprint.
To get a licence file and feature identifier take the following steps:
Copy the following template to a text file:
Web Application/Application Server
MachineID:
Fingerprint:
Please also include a suitable Cortex Innovation feature identifier.
From that folder, copy Cortex.Licensing.FingerprintGeneration.exe to the server.
Double-click Cortex.Licensing.FingerprintGeneration.exe to run it. A command line window will appear, containing a machine identifier and fingerprint, e.g:
MachineID: SERVER
Fingerprint: 111118BA104C928319E0CBAE30844CF8B7FD8BC414D1567844D1D0830089F1C9BF5C6
Copy the output (machine identifier and fingerprint) to the Web Application/Application Server section of the text file created in the initial step. Note that the machine identifier can be changed to any string.
Request a licence and feature identifier by raising a case in the Cortex Service Portal, including the contents of the text file containing all of the fingerprint and machine information in the body of the case.
When the licence and feature identifier have arrived, copy the file Cortex.lic to %ProgramData%\Cortex\Licences on the Web Application Server, creating the Cortex and Licences folders if they don’t exist. Save the feature identifier for use when Installing Gateway.
Web Browser Requirements
Gateway supports the latest versions of the following browsers:
Chrome
Edge
Firefox
Certificate Requirements
Note
For production systems it is recommended that an X.509 SSL certificate is obtained from a Certificate Authority and used for installation. For non-production systems, certificates can be omitted from installation and it will create and use self-signed certificates. This may prevent 3rd parties that require valid certificate verification to access the API Gateway Service.
An X.509 SSL certificate (standard or wildcard) should be used to:
Allow Application Services to identify themselves to clients such as Gateway.
Prevent unauthorised nodes from joining the single node cluster.
Connect to Service Fabric Explorer from the Application Server.
Connect to Gateway.
Allow Gateway to connect to the Flow Debugger Service.
The certificate can be obtained from a Certificate Authority, such as Let’s Encrypt, and must meet the following requirements:
Subject field must be in one of the following formats, depending on the certificate type:
Standard certificates must use the standard format (e.g. CN=host.domain.com).
Wildcard certificates must use the wildcard format, pertaining to the domain of the server (e.g. CN=*.domain.com).
Subject alternative names must include any additional host names that should be able to be used to access the API Gateway Service.
Subject Alternative Names (SAN): At minimum the FQDN of the server. It can also include NetBIOS Name, IP address, localhost, 127.0.0.1. It must include any additional host names that should be able to be used to access the API Gateway Service.
Certificate file must be in a .PFX file format, with a known password.
Certificate file must contain the full chain of certificates.
Certificate file must include the private key.
Key Usage extension must have a value of Digital Signature, Key Encipherment (a0).
Enhanced Key Usage must include Server Authentication and Client Authentication.
This file should be placed in a known location on the server. This location will be required when running the Application Server installation script.
Warning
It is critical to set a reminder to update certificates in good time before they expire. If they expire then the platform will cease to function and Cortex Service Portal must be contacted for support.
TLS Requirements
There is a set of non-compulsory security measures, recommended to be applied to the server, in order to prevent potential attacks that exploit known industry security vulnerabilities. This includes disabling all versions of SSL and TLS apart from TLS 1.2, and disabling all cipher suites apart from the following:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
See SSL Best Practices for a full list of the security changes which will be applied. The Cortex.Innovation.Install.SSLBestPractices.ps1 script is provided during installation to apply these security changes to the server.
Additional Application Server Requirements
Filesystem Requirements
The server must use an NTFS filesystem.
Service Requirements
The following Windows Services must be running on the server:
Remote Registry
Windows Event Log
Performance Logs & Alerts
Security Requirements
Installation User
A domain user which is a member of the Local Administrators group on the server must be available to run the installation scripts. This is a prerequisite of Microsoft Service Fabric, which is the platform that Cortex Innovation is built upon.
Antivirus Exclusions
It is advised (by Microsoft Service Fabric) that the following antivirus exclusions are created on the server to reduce antivirus processing on Service Fabric artefacts:
Folder Exclusions:
%ProgramFiles%\Microsoft Service Fabric
%ProgramData%\SF
%ProgramData%\SF\Logs
Process Exclusions:
Fabric.exe
FabricHost.exe
FabricInstallerService.exe
FabricSetup.exe
FabricDeployer.exe
ImageBuilder.exe
FabricGateway.exe
FabricDCA.exe
FabricFAS.exe
FabricUOS.exe
FabricRM.exe
FileStoreService.exe
A script is provided during installation to add these exclusions for Windows Defender. If any other antivirus software is running, these will need to be added manually.
If adding the exclusions manually, the Process Exclusions should be done before installation occurs, as the processes will be used during installation of the application and antivirus software can cause the installation to fail or timeout. Folder Exclusions may need to be added after installation has occurred as some antivirus software needs the folders to exist.
Port Requirements
Cortex Innovation and Microsoft Service Fabric require a range of firewall ports to be opened between the server and specific services.
If you are using Windows Firewall, some ports are opened during installation and others are opened dynamically as needed. If any other firewall is used, it will be necessary to add the rules described in Port Requirements to open the correct ports.
The Cortex.Innovation.Test.PortUsage.ps1 script is provided during installation to test the ports on the server and make sure they do not overlap with any other programs; most ports may be altered if this is the case, the description will say if this is not possible.
Additional Web Application Server Requirements
Security Requirements
Installation User
Domain users must be available to run the Application Pools for Gateway and Flow Debugger Service. These users must be given Log on as a service and Log on as a batch job permissions otherwise the Application Pools will not be able to run. Information about how to do this will be given during installation.
For Flow Debugger Service, the NETWORK SERVICE user can also be used.
Domain Requirements
For Gateway, only Windows domains with an Active Directory domain controller running Active Directory Domain Services are supported.
Supported versions of Active Directory are listed below:
Windows Server Standard and Datacenter editions are supported. Filesystem must be NTFS and networking must use IPv4. Linux is not supported, but may be in the future. ↩︎
SQL Server Express, Standard and Enterprise are supported. Other databases are not supported. Note that Transparent Data Encryption is not supported on SQL Server Express. ↩︎
PowerShell 5.1 ships with Windows Server 2016 and 2019. ↩︎
IIS is supported; other web servers, including IIS Express are not supported. ↩︎
Ships as a windows role within Windows Server 2019. ↩︎
Ships as a windows role within Windows Server 2016. ↩︎
3.1.1.2.3 - Install Application Server
Information about installing the Application Server.
Install Application Server
This guide describes how to install the Application Server components on the server. Please ensure that the Prerequisites have been read before starting this installation.
Make Installation Artefacts Available
Copy the following artefacts to a folder on the server (the version numbers may differ):
Cortex Innovation 2022.9 - Block Packages.zip
Cortex Innovation 2022.9 - App Services.zip
Cortex Innovation 2022.9 - App Server Install Scripts.zip
Extract the Cortex Innovation 2022.9 - App Server Install Scripts.zip file to a folder with the same name.
Install Microsoft .NET Framework 4.7.1
Microsoft Service Fabric requires a minimum of Microsoft .NET Framework 4.7.1 to be installed on the server.
To find the version of the framework that is installed:
On the Start menu, choose Run.
In the open box, enter regedit.exe. You must have administrative credentials to run regedit.exe.
In the Registry Editor, open the subkey HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full.
If the Full subkey is not present, then you do not have the .NET Framework 4.5 or later installed.
Check for a DWORD value named Release. The existence of the Release DWORD indicates the .NET Framework 4.5 or newer has been installed on that computer. If the value is 461308 or over then at least .NET Framework 4.7.1 is installed and no further steps need to be taken. If it is not installed, continue with the following steps to install it.
These are non-compulsory security measures, recommended to be applied to the server, in order to prevent potential attacks that exploit known industry security vulnerabilities.
Applying these measures may impact other applications running on your server. Therefore, it is your responsibility to ensure that other applications and their clients will not be affected by the changes.
Only Use Recommended Encryption Algorithms and TLS Protocols
A collection of registry settings need to be applied to guarantee your server is only using the recommended encryption algorithms and TLS protocols. Information about these settings can be found at SSL Best Practices.
Warning
Disabling specific TLS versions or specific Cipher Suites can have impact on Cortex components themselves as well as their communication capabilities with third party systems and services, e.g. Flow Debugger Service executing flows with blocks which communicate with 3rd parties via PowerShell or REST. All parties communicating together must support a shared protocol version and cipher suite, otherwise they will not be able to establish a secure communication link between each other.
The settings can be applied by running a script. Be aware that the server will be restarted when the script is run. Apply the settings by following these instructions:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Install.SSLBestPractices.ps1 script using the following command:
.\Cortex.Innovation.Install.SSLBestPractices.ps1
Note
To avoid answering all of the prompts -Override 0 can be added to the end of the script. This will automatically apply all settings and forcibly restart the server.
If -Override 0 has been specified no further steps need to be taken and you can move on to the next section when the server has restarted.
To use all the recommended settings click Apply all to the first prompt.
To selectively apply each setting select Choose which to apply. Each change will then be prompted with a Yes/No confirmation before applying.
Restart the machine when the script asks.
Add Antivirus Exclusions
If Windows Defender is not running on the server, ensure that the Antivirus Exclusions have been added to the running antivirus software on the server and continue to the next section, otherwise follow these steps:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Add.WindowsDefenderExclusions.ps1 script using the following command, modifying the ApplicationServers value to contain the NETBIOS name or fully qualified domain name of the server:
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on the server and press OK.
A message will indicate that the script has completed successfully.
Check Port Usage
To check all necessary ports are free, follow these steps.
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Test.PortUsage.ps1 script using the following command, modifying the ApplicationServers value to contain the NETBIOS name or fully qualified domain name of the server:
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on the server and press OK.
If all ports are free, the script will report the following:
All ports required by Cortex Innovation are free
If this is the case, continue to the next section. Otherwise, consult the messages returned by the script, which will give details about how to modify the Cortex.Innovation.Install.Config.json configuration file, in the Cortex Innovation 2022.9 - App Server Install Scripts folder, to use different ports. This will be used later during installation.
The Cortex.Innovation.Test.PortUsage.ps1 script cannot currently re-check modified ports in the configuration file so these need to be manually checked to see that they are free.
Configure Installation Script
In the Cortex Innovation 2022.9 - App Server Install Scripts folder, locate the Cortex.Innovation.Install.ps1 script and open it with a text editor.
Choose the tab below that matches the configuration for this installation, then update the script to match, changing the parameters according to the details given below:
Configure this value with the location of the App Services zip file on the server.
BlockPackagesPath
Configure this value with the location of the Block Packages zip file on the server.
ApiGatewayBasicAuthUserName
Configure this value with the username that will be used for Basic Authentication when making HTTPS requests to the API Gateway Service (e.g. starting production flows).
Currently only Basic Authentication using a single user is supported, OAuth2 will be supported in a future release.
Configure this value with the password that will be used for Basic Authentication when making HTTPS requests to the API Gateway Service (e.g. starting production flows). This should be Cortex Encrypted.
A name identifying the platform being installed. This must have no spaces or symbols. It will be appended to the node names that are displayed in Service Fabric Explorer.
ApplicationServerIPv4Addresses
The IPv4 address of the server.
ServerCertificatePath
The local path of a .PFX certificate file on the server. Environment variables cannot be used.
This is only needed if installing with CA Certificates (Recommended). The certificate should meet the Certificate Requirements.
This certificate will be used for:
Securing communication between the Application Services.
Allowing Application Services to identify themselves to clients such as Gateway.
Preventing unauthorised nodes from joining the single node cluster.
Connecting to Service Fabric Explorer from each of the Application Servers.
Warning
It is critical to set a reminder to update certificates in good time before they expire. If they expire then the platform will cease to function and Cortex Service Portal must be contacted for support.
ServerCertificatePwd
The password for the .PFX certificate file specified in ServerCertificatePath.
This is only needed if installing with CA Certificates (Recommended).
UseSelfSignedCertificates
Installs Application Services and required infrastructure using generated Self-Signed Certificates rather than CA Certificates.
Not recommended for production use.
SkipLoadBalancer
Installs Application Services and required infrastructure without installing a load balancer.
Credential
The credentials of the user which will be used to perform remote operations on the server. It must be a domain user that is a member of the local Administrators group on the server.
This does not need to be changed, a prompt will appear to enter this information when the script is run.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
More advanced configuration (such as changing ports) can be undertaken by modifying the Cortex.Innovation.Install.Config.json file but this shouldn’t be required for most installations. More information about this can be found at Advanced Application Server and Load Balancer Configuration Changes.
Save and close Cortex.Innovation.Install.ps1.
Test Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Type the following command into PowerShell:
.\Cortex.Innovation.Install.ps1-WhatIf
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to test the installation script.
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on the server and press OK.
A password prompt will appear. Enter a password which will be used to create a user in RabbitMQ.
Wait for the command to finish. It will display the output of the installation command without making any changes to the system.
Check that there have been no errors in the script; these would appear in red in the console.
If there are no errors, continue to the next section; otherwise, check if the errors have any instructions for rectifying the issue and follow them.
If there are no useful instructions, check that all previous steps have been followed correctly and, if not, rectify it and run the command again.
If this does not work, please contact Cortex Service Portal for further assistance. The WhatIf script will have created a temporary version of the config file in the script location, showing what changes would be made to it when the script runs. The name is appended with -WhatIf (e.g. Cortex.Innovation.Install.Config-WhatIf.json). This file can be provided when obtaining support.
Run Installation Script
Type the following command into PowerShell:
.\Cortex.Innovation.Install.ps1
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install HA Services and the required infrastructure.
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on the server and press OK.
A password prompt will appear. Enter a password which will be used to create a user in RabbitMQ. This should be entered carefully and recorded as it may be needed if seeking support from Cortex Service Portal. Press OK.
Wait for the script to finish running. This should take approximately 10 minutes.
Check that there have been no errors in the script; these would appear in red in the console.
If there are any errors, then please follow any instructions given within them to rectify the situation, check your configuration files, and retry the installation.
In some circumstances, retrying may error due to components being installed already. In this case please run the following command, followed by the original installation command:
Import the certificate, used in the ServerCertificatePath parameter of the Configure Installation Script section, to your Current User certificate store. This can be achieved by double clicking on the certificate .PFX file and following the wizard.
If using self-signed certificates, the certificate can be retrieved by using the Manage Computer Certificates tool in Windows to export the CortexServerCertificate from the Personal store and then importing it to the Current User store by double-clicking on it and following the wizard.
Open a web browser.
Navigate to https://server.domain.com:9080/Explorer, where server.domain.com is the fully qualified domain name of the server. Replace 9080 with new httpGatewayEndpointPort value if it was changed during configuration.
The screen should resemble that in the following figure:
Healthy Service Fabric Explorer Cluster
The status circles should be entirely green - this indicates that the node and all services and instances are healthy. Other status pages can be accessed by expanding items in the leftmost pane. Issues can be tracked down to the failing component by expanding items with warning triangles or error icons on. The next few diagrams show the status pages for a healthy system.
After expanding the application, clicking on any of the services should display a green circle and Status = Active:
Healthy Service Fabric Explorer Service
After expanding either of the services, clicking on any of the instances/partitions should display a green circle and Status = Ready:
Healthy Service Fabric Explorer Instance
Clicking on any of the nodes at the bottom of the leftmost pane should display a green circle and Status = Up:
Healthy Service Fabric Explorer Node
If any warning triangles appear, wait for 5 minutes or so as the cluster may still be starting up. If the cluster looks OK, go to the next section.
If the warnings persist or anything on the screen goes red, expand the items to find the individual services and instances which have errors or warnings. Warnings should not be ignored as they can indicate that the service can’t start but is still in the retry phase. Error and warning messages should be displayed on the status screens and should indicate what is wrong.
If no useful message can be seen here, the service log files may contain more information. These can be found on the server at:
%ProgramData%/Cortex/Cortex API Gateway Service
%ProgramData%/Cortex/Cortex Flow Execution Service
If no solution can be found, please contact Cortex Service Portal for further assistance.
Preserve installation files
Ensure that the installation files are backed up or kept on the server, especially the scripts and config files that have been modified. This will make it easier to perform further actions in future, such as troubleshooting, certificate rollover, uninstallation, reinstallation and updates.
Information about installing the Web Application Server.
Install the Web Application Server
This guide describes how to install the Web Application Server components on the server. Please ensure that Install Application Server has been completed before starting this installation.
Make Installation Artefacts Available
Copy the following artefacts to a folder on the server (the version numbers may differ):
Cortex Innovation 2022.9 - Web App Server Install Scripts.zip
Extract the Cortex Innovation 2022.9 - Web App Server Install Scripts.zip zip file to a folder with the same name.
Install Prerequisites
Licensing
Ensure that a valid Cortex licence file named Cortex.lic exists on the server, in the location %ProgramData%\Cortex\Licences. If it does not, follow the instructions located at Licensing Requirements.
Install SQL Server or SQL Express
Use one of the following installation guides to install SQL Server or SQL Server Express:
Gateway requires a minimum of Microsoft .NET Framework 4.7.1.
To find the version of the framework that is installed:
On the Start menu, choose Run.
In the open box, enter regedit.exe. You must have administrative credentials to run regedit.exe.
In the Registry Editor, open the subkey HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full.
If the Full subkey is not present, then you do not have the .NET Framework 4.5 or later installed.
Check for a DWORD value named Release. The existence of the Release DWORD indicates the .NET Framework 4.5 or newer has been installed on that computer. If the value is 461308 or over then at least .NET Framework 4.7.1 is installed and no further steps need to be taken. If it is not installed, continue with the following steps to install it.
Check if Web Deploy is already installed by going to Control Panel → Programs → Programs and Features; if Web Deploy is already installed, it will be listed as Microsoft Web Deploy.
If it is not installed, download Microsoft Web Deploy version 3.0 or later (WebDeploy_amd64_en-US.exe) to the server.
Double-click the downloaded file to start the installation.
Follow the installation wizard to install Web Deploy; on the Choose Setup Type page select Typical.
Install Visual C++ Redistributable
Check if Visual C++ 2013 Redistributable (x64) is already installed by going to Control Panel → Programs → Programs and Features; if Visual C++ Redistributable is already installed, it will be listed as Microsoft Visual C++ 2013 Redistributable (x64).
Double-click the downloaded file to start the installation.
Follow the installation wizard to install the Visual C++ Redistributable.
IIS Role Setup and Configuration
Install Internet Information Services (IIS)
Install the required features by following these instructions:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Web App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Web App Server Install Scripts"
Run the Cortex.Innovation.Install.WindowsFeatures.ps1 script using the following command, this may take a few minutes:
.\Cortex.Innovation.Install.WindowsFeatures.ps1
Check the output is as follows:
Web-WebSockets is installed
Web-Asp-Net45 is installed
Web-Net-Ext45 is installed
Web-ISAPI-Ext is installed
Web-ISAPI-Filter is installed
Net-Framework-45-Core is installed
Net-Framework-45-ASPNET is installed
Web-Default-Doc is installed
Web-Dir-Browsing is installed
Web-Http-Errors is installed
Web-Static-Content is installed
Web-Http-Logging is installed
Web-Http-Redirect is installed
Web-Request-Monitor is installed
Web-Stat-Compression is installed
Web-Dyn-Compression is installed
Web-Filtering is installed
Web-Windows-Auth is installed
Web-Mgmt-Console is installed
Web-Mgmt-Service is installed
Register and Allow .NET CLR v4.0.30319 with IIS
Note
Unless .NET CLR v4.0.30319 is registered and allowed with IIS, Gateway and Flow Debugger Service will not work.
Open a Windows PowerShell (x64) window as administrator.
Once PowerShell confirms that it has finished installing .NET CLR v4.0.30319, close the PowerShell window.
Install URL Rewrite Module
The URL Rewrite IIS Manager module is required to enable web applications on your server to rewrite URLs. This is needed to allow HTTP URLs to redirect to the equivalent HTTPS ones.
To install the URL Rewrite module take the following steps:
In the left-hand pane of Internet Information Service (IIS) Manager, select the server node.
Ensure that there is an icon with the title URL Rewrite under the IIS feature section:
Url Rewrite Module Icon
If there is an icon, URL Rewrite module is installed and no further steps are required.
If there is no icon, the module is not installed and the following steps must be taken:
After successfully installing, close and reopen IIS Manager. The URL Rewrite icon should now be visible.
Add HTTPS Firewall Rule
If any firewall is running on the server, it must be configured to allow communication inbound via TCP on the port configured for HTTPS (usually 443). See Configure Firewalls for information about adding rules to Windows Firewall.
Create Web Site
Gateway and Flow Debugger Service can either be installed to an existing web site or a newly created web site. If you are installing into an existing web site skip to Configure Web Site.
The steps to create a new web site are:
In Windows File Explorer, navigate to the default IIS folder (usually %SystemDrive%\inetpub\wwwroot, e.g. C:\inetpub\wwwroot).
Ensure there is a folder called Cortex; if not create it.
In the left-hand pane of Internet Information Service (IIS) Manager, expand the server node.
Right-click the Sites node under the server and select Add Website….
Set the Site name to Cortex.
Set the Physical path to the folder created above (e.g. C:\inetpub\wwwroot\Cortex), by clicking on the ellipses …, selecting the appropriate directory and clicking OK.
Click OK. If an existing site is already using the specified port, a warning will be displayed. Either click No and change the Port in the Add Website dialog, or click Yes and stop the other website.
Configure Web Site
The web site which the Gateway and Flow Debugger Service are installed under requires additional configuration.
Configure HTTPS
Both the Gateway and Flow Debugger Service should be configured to use HTTPS:
Note
For sites using self-signed SSL certificates, the HTTPS URL redirection will only work in Google Chrome browsers. For all other supported browsers, an SSL certificate signed by a Certificate Authority must be used to enable HTTPS URL redirection.
In the left-hand pane of Internet Information Service (IIS) Manager, expand the server node.
Expand the Sites node under the server.
Right-click the web site where Gateway will be installed and select Edit Bindings….
Click Add…
Set Type to https.
Set the appropriate Port number (typically 443). The Host name box can be left blank.
Note
Configuring your system to use a port other than the HTTPS default of 443 is not compatible with HTTP Strict Transport Security (HSTS). If your configuration requires HTTPS to run on a port other than 443, the HSTS configuration must be turned off. This can be achieved by configuring the Add Strict-Transport-Security when HTTPS rewrite rule’s enabled setting to false in web.config after installation.
Select the SSL certificate that was used when installing the Application Server. If self-signed certificates were used, this will have the subject CN=CortexServerCertificate.
Click OK. If an existing site is already using the specified SSL port, a warning will be displayed. Either click No and change the Port in the Add Site Binding dialog, or click Yes and stop the other website.
It is recommended to remove the http site binding.
Install Flow Debugger Service
Get Application Pool User
A domain user account is required for the Flow Debugger Service web application pool and must be created prior to performing the installation. In line with best practices, this account should not be used for any purposes other than those specified for the Flow Debugger Service. Alternatively, the NETWORK SERVICE user may also be used.
This user must currently have access to the default NuGet directory, in order to load block packages correctly. To add permissions for the user take the following steps:
Navigate to %SystemRoot%\System32\config\systemprofile\AppData\Roaming\ and create a new folder named NuGet if one does not exist.
Right-click on the NuGet folder and click Properties.
In the dialog, click the Security tab.
Click the Edit... button.
Click the Add... button.
Enter the username of the application pool user and click OK.
In the Permissions section at the bottom, check Full control
Click OK.
The user must be given Log on as a service and Log on as a batch job permissions. To do this take the following steps:
Navigate to Start -> Administrative Tools -> Local Security Policy.
In the Local Security Policy dialog, expand the Local Policies node then select User Rights Assignment.
Take the following steps for the Log on as a service and Log on as a batch job policies:
In the right-hand panel, double-click on the policy.
In the Properties dialog, click on the Add User or Group button.
Note
It is possible to use the Advanced… button to look up names rather than entering them manually. Various filters can be set to find the correct user or group more easily. Multiple users can be selected by holding down CTRL while clicking. OK adds the selected users or groups into the Enter the object names to select text box.
Type the name of the application pool user account into the Enter the object names to select text box. Click the Check Names button to confirm that the user exists.
Click OK on the Select Users dialog, and then confirm the user is correct by clicking OK on the Properties dialog.
Configure Installation Script
In the Cortex Innovation 2022.9 - Web App Server Install Scripts folder, locate the Cortex.Innovation.Install.FlowDebuggerService.ps1 script and open it with a text editor.
Choose the tab below that matches the configuration for this installation, then update the script to match, changing the parameters according to the details given below:
Configure this value with the password that will be used for Basic Authentication when Gateway makes HTTPS requests to the Flow Debugger Service.
This password should be Cortex Encrypted. For security reasons it is recommended that the default value ADA9883B11BD4CDC908B8131B57944A4 should be changed.
Enables Flow Debugger Service to communicate with Gateway using generated Self-Signed Certificates rather than CA Certificates.
Not recommended for production use.
Credential
The credentials of the user that will be used to run the Debugger application pool in IIS.
This does not need to be changed, a prompt will appear to enter this information when the script is run.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
Save and close Cortex.Innovation.Install.FlowDebuggerService.ps1.
Run Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Web App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Web App Server Install Scripts"
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install the Flow Debugger Service.
A credentials prompt will appear. Enter the credentials of the user that should run the Debugger application pool in IIS. If using the NETWORK SERVICE user, enter any user as the username and leave the password blank; the NETWORK SERVICE user will need to be selected in the final step.
Wait for the script to finish running. This should take approximately 2 minutes.
An error may have appeared saying:
The Windows Process Activation Service service is not started.
This can be ignored.
Check that there have been no other errors in the script; these would appear in red in the console.
If there are any errors, then please follow any instructions given within them to rectify the situation, and retry the installation.
If the errors do not give any instructions on how to rectify, please contact Cortex Service Portal for further assistance.
If using NETWORK SERVICE for the application pool user:
Open Internet Information Services (IIS) Manager.
On the left, expand the server node.
Click Application Pools.
Right-click on the Debugger application pool and select Advanced Settings....
In the Advanced Settings dialog, click on Identity and then click the ellipses (...).
In the Application Pool Identity dialog, select Built-in account, then select NetworkService from the drop-down, then click OK.
Right-click on the Debugger application pool and click Recycle....
Install Gateway
Get Application Pool User
A domain user account is required for the Gateway web application pool and must be created prior to performing the installation
below.
This user account is required to enable Gateway to access the Cortex database, with the following roles:
dbcreator
public
To add roles to database users take the following steps:
Open SQL Server Management Studio on the server and log in.
Expand the server node, then Security then Logins.
If the user that will run the Gateway application pool is not in the list of logins, take the following steps, otherwise skip to step 4:
Right-click the Logins node and click New Login....
Enter the application pool user in the Login name box.
On the left pane, click Server Roles.
Check public and dbcreator
Click OK.
If the user that will run the Gateway application pool is in the list of logins, take the following steps:
Right-click on the application pool user.
Click Properties.
On the left pane, click Server Roles.
Check public and dbcreator.
Click OK.
In line with best practices, this account should not be given administrator rights, nor should it be used for any purposes other than those specified for Gateway.
The user must be given Log on as a service and Log on as a batch job permissions. To do this take the following steps:
Navigate to Start -> Administrative Tools -> Local Security Policy.
In the Local Security Policy dialog, expand the Local Policies node then select User Rights Assignment.
Take the following steps for the Log on as a service and Log on as a batch job policies:
In the right-hand panel, double-click on the policy.
In the Properties dialog, click on the Add User or Group button.
Note
It is possible to use the Advanced… button to look up names rather than entering them manually. Various filters can be set to find the correct user or group more easily. Multiple users can be selected by holding down CTRL while clicking. OK adds the selected users or groups into the Enter the object names to select text box.
Type the name of the application pool user account into the Enter the object names to select text box. Click the Check Names button to confirm that the user exists.
Click OK on the Select Users dialog, and then confirm the user is correct by clicking OK on the Properties dialog.
Create Gateway Application Pool
Open Internet Information Services (IIS) Manager.
Select and right-click the Application Pools node under the server and select Add Application Pool…
Set Name to Cortex Gateway.
Ensure that the .NET CLR version is set to .NET CLR Version v4.0.30319 (This may be configured by default).
Ensure that the Managed pipeline mode is set to Integrated (This may be configured by default).
Click OK
Right click on the created application pool and select Advanced Settings…
Click the ... next to Identity (under Process Model) to open a dialog, then select Custom Account and Set....
Click OK to close the Application Pool Identity dialog.
Click OK to close the Advanced Settings dialog.
Create New Web Application
In the left-hand pane of Internet Information Service (IIS) Manager, expand the server node.
Right-click on the site the application should be installed under and select Add Application…
Set the Alias to gateway. This must be lowercase.
Click Select… and from the Application pool dropdown select the Cortex Gateway application pool and click OK.
Set the Physical path to C:\inetpub\wwwroot\Cortex\Gateway by clicking on the ellipses … and selecting the appropriate directory. Create the C:\inetpub\wwwroot\Cortex\Gateway directory if it does not already exist.
Click OK.
Configure IIS Site Redirect to the Specified Web Application (Optional)
If the site hosting the Gateway web application is a newly created Cortex site or an existing site that doesn’t have its own content, it is recommended to redirect the site URL to the gateway web application URL, e.g. https://FullyQualifiedDomainName to https://FullyQualifiedDomainName/gateway.
Open Internet Information Services (IIS) Manager.
Select the site hosting the gateway web application and from IIS settings double-click the HTTP Redirect icon.
Click the check box Redirect requests to this destination.
Enter https://FullyQualifiedDomainName/gateway, replacing FullyQualifiedDomainName with the FQDN of the server.
In the Redirect Behaviour section, click Only redirect requests to content in this directory (not subdirectories).
In Actions click the Apply button.
Configure Installation Script
In the Cortex Innovation 2022.9 - Web App Server Install Scripts folder, locate the Cortex.Innovation.Install.Gateway.ps1 script and open it with a text editor.
Configure the script according to the details given below:
Configure this value with the location of the Cortex Innovation 2022.9 - Gateway.zip file on the installation server.
GatewayApplicationIISPath
Change to the correct Site Name/Application if either was modified from the defaults (Cortex/gateway) when creating the website or application.
ModelDBContextConnectionString
If SQL Server was installed as the default instance, change the Data Sourcein the connection string to localhost.
If SQL Server was installed as a named instance, change it to .\{instanceName} replacing {instanceName} with the name of the instance.
This will set the ModelDBContextConnectionString value in the Gateway web.config.
AuthContextConnectionString
If SQL Server was installed as the default instance, change the Data Sourcein the connection string to localhost.
If SQL Server was installed as a named instance, change it to .\{instanceName} replacing {instanceName} with the name of the instance.
This will set the AuthContextConnectionString value in the Gateway web.config.
SignalRContextConnectionString
If SQL Server was installed as the default instance, change the Data Sourcein the connection string to localhost.
If SQL Server was installed as a named instance, change it to .\{instanceName} replacing {instanceName} with the name of the instance.
This will set the SignalRContextConnectionString value in the Gateway web.config.
FeatureFlags
Replace InnovationId with the Cortex Innovation feature identifier, which should have been provided by Cortex when fulfilling the Licensing Requirements, if it wasn’t it should be requested using Cortex Service Portal.
This will set the FeatureFlags value in the Gateway web.config.
ServiceFabricApiGatewayEndpoint
Replace server.domain.com with the fully qualified domain name of the server. The port should be specified as 8722 and there must be a trailing slash, e.g. https://server.domain.com:8722/.
This will set the ServiceFabricApiGatewayEndpoint value in the Gateway web.config.
ServiceFabricUsingSelfSignedCertificates
Configure the value as $false if you used valid CA certificates when installing the Application Server, $true if you used self-signed certificates.
This will set the ServiceFabricUsingSelfSignedCertificates value in the Gateway web.config.
ServiceFabricApiGatewayBasicAuthUsername
This must be changed if you used a non-default ApiGatewayBasicAuthUserName when installing the Application Server; if so, this value must be configured to the one used.
This will set the ServiceFabricApiGatewayBasicAuthUsername value in the Gateway web.config.
ServiceFabricApiGatewayBasicAuthPassword
This must be changed if you used a non-default ApiGatewayBasicAuthPassword when installing the Application Server; if so, this value must be configured to the one used. It can be Cortex Encrypted.
This will set the ServiceFabricApiGatewayBasicAuthPassword value in the Gateway web.config.
DotNetFlowDebuggerEndpoint
Replace server.domain.com with the fully qualified domain name of the Web Application Server.
This will set the DotNetFlowDebuggerEndpoint value in the Gateway web.config.
DotNetFlowDebuggerBasicAuthUsername
This must be changed if you used a non-default FlowDebuggerBasicAuthUserName when installing the Flow Debugger Service; if so, this value must be configured to the one used.
This will set the DotNetFlowDebuggerBasicAuthUsername value in the Gateway web.config.
This will set the DotNetFlowDebuggerBasicAuthPassword value in the Gateway web.config.
DotNetFlowDebuggerUsingSelfSignedCertificates
Configure the value as $false if you are using valid CA certificates to secure the site containing Gateway and Flow Debugger Service, $true if using self-signed certificates.
This will set the DotNetFlowDebuggerUsingSelfSignedCertificates value in the Gateway web.config.
Test
This does not need to be changed, it will be set at a later stage.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
Save and close Cortex.Innovation.Install.Gateway.ps1.
Test Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Web App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Web App Server Install Scripts"
Type the following command into PowerShell:
.\Cortex.Innovation.Install.Gateway.ps1-Test
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to test the configuration.
In the event of any errors, there will be an error message displayed at the end of the output with a line confirming the Error Count.
Run Installation Script
Ensure the Gateway application pool is stopped:
Open Internet Information Service (IIS) Manager.
In the left pane, expand the server node.
Click Application Pools to display a list of the Application Pools.
Right-click the Cortex Gateway application pool and select Stop.
Note
Failure to stop the application pool will result in a permissions error when installing Gateway.
Type the following command into PowerShell:
.\Cortex.Innovation.Install.Gateway.ps1
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install Gateway.
In the event of any errors, there will be an error message displayed at the end of the output with a line confirming the Error Count.
Click OK, then wait for Windows Security to update the security information to the folder.
Click OK.
Start the Gateway application pool:
Open Internet Information Service (IIS) Manager.
In the left pane, expand the server node.
Click Application Pools to display a list of the Application Pools.
Right-click the Cortex Gateway application pool and select Start.
Once the application pool has been started, the site will be available on <protocol>://<host>:<port>/<webapplicationname>, e.g. https://localhost/gateway.
Note
If the application pool does not stay started, ensure that the user it runs as has Log on as a service and Log on as a batch job permissions or belongs to a group that has those permissions.
Preserve installation files
Ensure that the installation files are backed up or kept on the server, especially the scripts and config files that have been modified. This will make it easier to perform further actions in future, such as troubleshooting, certificate rollover, uninstallation, reinstallation and updates.
Follow the steps in the setup wizard to configure the relevant areas:
Account Details
Click Next Step:
Initial Setup Screen
Enter an email address for the Administrator and click Next Step:
Administrator Details Screen
Change the Administrator password to a unique, secret password and click Next Step:
Change Password Screen
LDAP Connection
Enter the details of your Active Directory server and provide a Username and Password for a user with read access to it:
A connection to an Active Directory server must be established in order to assign authorisation rights to users.
In the Server field, enter the Hostname, FQDN or IP Address of the Active Directory server that Gateway should use to authenticate and authorise users.
In the Port field, enter the port number of the Active Directory server. The well-known port for LDAP traffic is 389; if SSL encryption is used, the well-known port is 636.
If an SSL connection is to be used, tick the box Use SSL.
In the Username field, enter a valid username of a user that has read permissions for the Active Directory server.
In the Password field, enter the password of the user entered in the previous step.
To reduce the scope of any Active Directory searches, add one or more base DNs (Distinguished Names). For each base DN click Add and enter the full LDAP path e.g CN=group, OU=organisational unit, DC=domain, DC=com. These will be used as the roots of any Active Directory searches performed. For more information about distinguished names see https://msdn.microsoft.com/en-us/library/aa366101(v=vs.85).aspx.
Click Test Connection to validate the connection and the user credentials entered and click Next Step.
LDAP Connection Screen
LDAP Authorisation
If the authorisation grid fails to load first time round, click Retry.
Assign access permissions to Active Directory groups:
To allow users to access the various roles within Gateway, it is first necessary to assign them the appropriate access rights.
Gateway currently supports four roles, but only two are relevant for Cortex Innovation:
Admin
Studio
To give a user access to a role, set access for a group or Organisational Unit (OU) that the user is a member of:
Expand the groups or OUs, or search for the group or OU, to be assigned one or more roles.
Check the relevant roles for each group. Checking a parent group will cascade the setting to all child groups.
LDAP Authorisation Screen
Click Complete Setup to commit the changes.
To test the permissions, log out as Administrator and then log in as a user with Studio permissions.
Configure the Gateway Databases to use Transparent Data Encryption
Note
Transparent Data Encryption cannot be applied to SQL Express, only SQL Server instances.
Once Gateway has been configured, if you wish to encrypt the databases using Transparent Data Encryption for improved security, this should now be performed by following the steps in Configuring TDE.
Information about trying out Cortex Innovation for the first time.
Try it out
This guide describes how to try out a new Innovation installation to make sure it is working. Please ensure that Setup Gateway has been completed before taking these steps.
Test Debugging Flows
Test the platform by creating a new flow and executing it using the following steps:
Click on the Flows charm, then the + button and click Group to open a dialog.
Enter a name for the group, configure the Permission Groups and click OK to create the group.
Click on the group to open it (refresh the page if it does not appear).
Inside the group, click the + button again and click on Flow to open a dialog. If the menu item is not present, it means that the FeatureFlags in the CortexGateway.SetParameters.xml file was not set properly when installing Gateway. See Troubleshooting for more information.
Enter a name for the flow, configure the Permission Groups and click OK to create the flow.
The flow should be displayed with a start flow block and end flow block. A list of block palettes should be displayed down the left hand side:
New Flow - Number of palettes may differ
If the blocks in the flow do not display or the palettes are not visible, see Troubleshooting for more information.
Add a Set Variable block and connect it between the start and end blocks.
Click the Set Variable block to open the Property Editor.
Set the Value property to the expression DateTimeOffset.Now.
Type Result into the Variable property and click Create Result.
In the Variable Editor, set Is Output Variable? to true for the new Result variable.
Set a breakpoint on the end block and start the flow. An execution token should appear, the Result variable should show the current time. If the token does not appear, try refreshing the page.
Continue or stop the execution.
Commit the flow.
Test Publishing Production Flows
Log in to Gateway with a user that has the Admin role.
Click on the Settings charm, then Packages.
Click Add Package Definition. Enter a package name and select the new flow to add to the package. Click Save to save the new package.
Click Publish. A success message should appear. If it doesn’t it means that either one or more of the parameters prefixed with Service Fabric in the CortexGateway.SetParameters.xml file was not set properly when installing Gateway, or the Application Services aren’t healthy. See Troubleshooting for more information.
Test Executing Production Flows
Open an HTTP client, such as Postman. Make a request with the following format:
Property
Value
Action
POST
URL
https://{FQDN of server}:8722/api/default/default/flows/{Flow Name}/executions?packageName={Package Name} e.g. https://server.domain.com:8722/api/default/default/flows/NewFlow/executions?packageName=NewPackage
Content Type
application/json
Body
{}
Authentication
Basic
Username
The value used for ApiGatewayBasicAuthUserName when installing Application Services
Password
The value used for ApiGatewayBasicAuthPwd when installing Application Services (Unencrypted)
Note
If you used self-signed certificates when installing the server you will need to disable SSL certificate validation in your HTTP client.
The request should return a JSON object with the output variables of the flow e.g. { "Output": "2022-03-09T07:35:16+0000" }.
Cortex Innovation has now been verified and is ready to use.
3.1.1.3 - Advanced Setup
Supporting information about installing Cortex Innovation with non-default configurations.
3.1.1.3.1 - Advanced Application Server and Load Balancer Configuration Changes
Information about installing Cortex Innovation with non-default installation values.
Advanced Application Server and Load Balancer Configuration Changes
Advanced configuration (such as port changes) can be undertaken by taking the following steps before running the PowerShell script. Some values will be modified by the script and they will take precedence, but those parameters can be removed from the script and this file used entirely if required.
Multiple Server With HA
In the Cortex Innovation 2022.9 - Installation Scripts folder, locate the file Cortex.Innovation.Install.Config.json and open it with a text editor.
Change the configuration file according to your cluster, referring to the following example and details:
A name identifying the platform being installed. This should have no spaces or symbols. It will be appended to the node names that are displayed in the Service Fabric management tool.
16-24
If the bundled load balancer is not being used, delete these lines
17
A local empty or non-existent directory on the load balancer server that the load balancer can be installed in. The directory path will be created if it does not exist. The installation user must have permissions to create and write to directories here. Ensure that all backslashes are escaped with another backslash. Environment variables may be used.
18
The IPv4 address of the server that the load balancer should run on.
21
The port that the HTTPS load balancer server should run on. This port should not be in use by anything else.
22
The port that the API Gateway Service is running on the Application Servers. This should be 8722.
23
The name of a certificate entry in the adminCertificates section. If this line is removed, an auto-generated self-signed certificate will be used.
27, 31, 35
The short computer names of the Application Servers. These must not contain the domain. The installation will be run on the first of these nodes.
28, 32, 36
The respective IPv4 addresses of the Application Servers.
42, 46, 50
These keys should be changed to the computer names of the Application Servers to match those on lines 26, 30 and 24
44, 48, 52
The name of a certificate entry in the serverCertificates section. This should be the same for all Application Servers. If these lines are removed, an auto-generated self-signed certificate will be used. Self-signed certificates are not recommended for production systems.
73-75
Skip configuring these lines if self-signed certificates are being used.
80-82
Skip configuring these lines if self-signed certificates are being used or if the bundled load balancer is not being used.
74
This is the local path of a .PFX certificate file on the first Application Server, containing a full chain certificate with private key. Ensure that all backslashes are escaped with another backslash. Environment variables cannot be used.
75
The password used to secure the .PFX file.
76
This only needs to be used if the installation has failed due to a missing root certificate. See Troubleshooting Root Certificate Error for information.
81
This is the local path of a .PFX certificate file on the first Application Server, containing a full chain certificate with private key. Ensure that all backslashes are escaped with another backslash. Environment variables cannot be used.
82
The password used to secure the .PFX file.
83
This only needs to be used if the installation has failed due to a missing root certificate. See Troubleshooting Root Certificate Error for information.
Save and close the config file.
Single Server Without HA
In the Cortex Innovation 2022.9 - Installation Scripts folder, locate the file Cortex.Innovation.Install.Config.json and open it with a text editor.
Change the configuration file according to your cluster, referring to the following example and details:
A name identifying the platform being installed. This should have no spaces or symbols. It will be appended to the node names that are displayed in the Service Fabric management tool.
18
The short computer names of the node. This must not contain the domain. The installation will be run on the this node.
19
The IPv4 address of the node.
25
This key should be changed to the computer names of the node to match that on line 18
27
The name of a certificate entry in the serverCertificates section. If this line is removed, an auto-generated self-signed certificate will be used. Self-signed certificates are not recommended for production systems.
48-50
Skip configuring these lines if self-signed certificates are being used.
48
This is the local path of a .PFX certificate file on the server, containing a full chain certificate with private key. Ensure that all backslashes are escaped with another backslash. Environment variables cannot be used.
49
The password used to secure the .PFX file.
50
This only needs to be used if the installation has failed due to a missing root certificate. See Troubleshooting Root Certificate Error for information.
Save and close the config file.
3.1.1.3.2 - Configure Firewalls
Information about configuring Firewalls, e.g. adding rules.
Configure Firewalls
Add Inbound Rules to Windows Firewall
To set up inbound rules for Windows Firewall take the following steps for each rule that you want to add:
Navigate to Start → Administrative Tools → Windows Firewall with Advanced Security.
In the left-hand panel, click on the Inbound Rules node.
In the right-hand panel, click on New Rule.
In the New Inbound Rule Wizard, select the Port option then click on the Next >
button.
Select either TCP or UDP depending on the rule that is being made.
Select Specific local ports.
Enter the required ports in a comma separated list (e.g. 443, 80) in the text box and press Next >.
Select Allow the connection then click Next >.
Click Next > again, then add an identifiable name for the rule
Click Finish.
3.1.1.3.3 - Configure the Gateway Databases to use Transparent Data Encryption
Information about configuring Gateway Databases to use Transparent Data Encryption.
Configure the Gateway Databases to use Transparent Data Encryption
Once the Gateway Setup steps have been completed, if you wish to encrypt the databases using Transparent Data Encryption (TDE) for improved security, this should now be performed.
Note
TDE cannot be applied to SQL Express, only SQL Server instances.
Enabling TDE on the databases ensures that the data is encrypted on disk. The process to do this requires that you:
Create a master key in the master database with a strong password. This password must be remembered and/or saved in a secure location to enable decryption of the database later.
Create a certificate within SQL Server.
Backup the certificate and store it in a secure location. If a database needed to be restored elsewhere for any reason the certificate will need to be imported to the new server.
Create a database encryption key in each user database to be encrypted.
Enable encryption on the database.
To enable TDE on the suite of Gateway Databases you should complete the following steps:
Open SQL Server Management Studio.
Open the Cortex.Install.TDE.sql script included within the Cortex Innovation 2022.9 - Web App Server Install Scripts folder.
Note
This script will attempt to encrypt all Cortex Databases that exist on the system. Any that do not exist will be skipped. If you do not wish to encrypt all existing Cortex Databases then you should contact Cortex Service Portal for assistance with script modification.
Set the @sPassword parameter value to a password that you wish to use.
Note
This password must be set to a value that is not a blank or empty string, it cannot be null and the script will not execute if it is not changed from the pre-populated value of StrongPassword. The password must also meet your system’s minimum security requirements.
You can change the names of the certificate and the name of the master key by changing the @sCertName and @sKeyName parameters if you so wish.
You can change the location that the certificate and key are backed up to by changing the value of the @sBackupLocation parameter.
The location must already exist, and there must not be any files within the specified location with the same name as the certificate or master key names that have been specified.
The user that this script will be executed as must also have write permissions to this location.
Once the parameters have been set appropriately you should now save the script.
We recommended that the modified script is saved out to file (taking care to observe your own organisation’s security policies for password management), before it is executed. This may help facilitate the support process if anything goes wrong.
Click Execute to run the script. It may take several minutes to execute depending on the size of the databases.
Once the script has completed successfully, you should move the backed-up certificate and master key to a secure location and the password specified should also be stored securely.
3.1.1.3.4 - Create Self-Signed Certificates
Information about creating and installing self-signed certificates.
Create Self-Signed Certificates
Self-signed certificates should be generated using OpenSSL which is bundled in the Cortex Web App Server Install Scripts:
Setup OpenSSL in PowerShell
Open a Windows PowerShell (x64) window as administrator.
Make a directory in which to store the certificates by running the following command, changing the path as required:
mkdirC:\Certificates
Navigate PowerShell to inside the certificates folder created above, using the following command, modifying the path as necessary:
cd "C:\Certificates"
Temporarily add OpenSSL to the Path environment variable of your system by running the following command, modifying the path according to the location of openssl.exe in the installation scripts on the machine:
$env:PATH+=";C:\Cortex Innovation 2022.9 - Web App Server Install Scripts\OpenSSL"
Generate the Root CA Certificate
Create the Root CA private key by running the following command:
opensslgenrsa-outcortexCA.key4096
Generate the Root CA certificate signed with the private key:
Copy the following text into a text editor:
RANDFILE= .rnd
[ ca ]default_ca= CA_default # The default ca section[ CA_default ]# Directory and file locations.# SHA-1 is deprecated, so use SHA-2 instead.default_md= sha256
policy= policy_strict
[ policy_strict ]# The root CA should only sign intermediate certificates that match.# See the POLICY FORMAT section of `man ca`.countryName= match
stateOrProvinceName= match
organizationName= match
organizationalUnitName= optional
commonName= supplied
emailAddress= optional
[ req ]# Options for the `req` tool (`man req`).default_bits=2048distinguished_name= req_distinguished_name
string_mask= utf8only
# SHA-1 is deprecated, so use SHA-2 instead.default_md= sha256
# Extension to add when the -x509 option is used.x509_extensions= v3_ca
[ req_distinguished_name ]countryName= Country Name (2 letter code)countryName_min=2countryName_max=2stateOrProvinceName= State or Province Name (full name)localityName= Locality Name (eg, city)0.organizationName = Organization Name (eg, company)organizationalUnitName= Organizational Unit Name (eg, section)commonName= Common Name (eg, your website's domain name)commonName_max=64emailAddress= Email Address
emailAddress_max=40# Optionally, specify some defaults.countryName_default= GB
stateOrProvinceName_default= Hampshire
localityName_default= Southampton
0.organizationName_default = Cortex Ltd
organizationalUnitName_default= Cortex
emailAddress_default= info@cortex.co.uk
[ v3_ca ]# Extensions for a typical CA (`man x509v3_config`).subjectKeyIdentifier=hashauthorityKeyIdentifier= keyid:always,issuer
basicConstraints= critical, CA:true
keyUsage= critical, digitalSignature, cRLSign, keyCertSign
Save the file as ca.cnf in the directory created for the certificates above.
In the PowerShell window, run the following command:
Enter a memorable string as the Export Password when asked, this will be needed when adding the certificate to certmgr.
Double click on the cortexCA.pfx file in the certificates folder to import the certificate into the Windows Certificate Store. Perform the following steps:
Select Local Machine then click Next.
Click Next.
Enter the Export Password which the certificate was generated with then click Next.
Select Place all certificates in the following store.
Click Browse….
Select Trusted Root Certification Authorities, click OK then click Next.
Click Finish.
Generate the Certificate
Create a private key for the SSL cert by running the following command:
opensslgenrsa-outcortex.key2048
Generate the SSL certificate request:
Copy the following text into a text editor:
RANDFILE= .rnd
[ ca ]default_ca= CA_default # The default ca section[ CA_default ]# SHA-1 is deprecated, so use SHA-2 instead.default_md= sha256
policy= policy_loose
[ policy_loose ]# Allow the intermediate CA to sign a more diverse range of certificates.# See the POLICY FORMAT section of the `ca` man page.countryName= optional
stateOrProvinceName= optional
localityName= optional
organizationName= optional
organizationalUnitName= optional
commonName= supplied
emailAddress= optional
[ req ]# Options for the `req` tool (`man req`).default_bits=2048distinguished_name= req_distinguished_name
string_mask= utf8only
# SHA-1 is deprecated, so use SHA-2 instead.default_md= sha256
# Extension to add when the -x509 option is used.x509_extensions= v3_req
req_extensions= v3_req
[ req_distinguished_name ]countryName= Country Name (2 letter code)countryName_min=2countryName_max=2stateOrProvinceName= State or Province Name (full name)localityName= Locality Name (eg, city)0.organizationName = Organization Name (eg, company)organizationalUnitName= Organizational Unit Name (eg, section)commonName= Common Name (eg, your website's domain name)commonName_max=64emailAddress= Email Address
emailAddress_max=40# Optionally, specify some defaults.countryName_default= GB
stateOrProvinceName_default= Hampshire
localityName_default= Southampton
0.organizationName_default = Cortex Ltd
organizationalUnitName_default= Cortex
emailAddress_default= info@cortex.co.uk
[ v3_req ]basicConstraints= CA:FALSE
keyUsage= nonRepudiation, digitalSignature, keyEncipherment
subjectAltName= @alt_names
[ alt_names ]# Specify all DNS and/or IP addresses that clients can use to access the secured resource.DNS.1 = MACHINE-NAME
DNS.2 = FULLY QUALIFIED MACHINE NAME
DNS.3 = localhost
IP.1 = IP ADDRESS
IP.2 = 127.0.0.1
Modify the section [alt_names] to include all the required DNS names and IP addresses that clients can use to access the secured resource.
Each DNS name or IP address entry must be suffixed with .N where N is the unique index of the DNS name or IP address entry; see below for examples:
Resource URL
Configuration to add
https://cortex.co.uk/gateway
DNS.1 = cortex.co.uk
https://internal.cortex.co.uk/gateway
DNS.2 = internal.cortex.co.uk
https://10.0.0.0/gateway
IP.1 = 10.0.0.0
https://192.168.1.100/gateway
IP.2 = 192.168.1.100
Save the file as san.cnf in the directory created for the certificates above.
In the PowerShell window, run the following command:
Enter a memorable string as the Export Password when asked, this will be needed when adding the certificate to certmgr.
Import the Certificate
Double click on the cortex.pfx file in the certificates folder to get the certificate imported to the Windows Certificate Store. Perform the following steps:
Select Local Machine then click Next.
Click Next.
Enter the Export Password which the certificate was generated with then click Next.
Select Place all certificates in the following store.
Click Browse….
Select Personal, click OK then click Next.
Click Finish.
3.1.1.3.5 - Encrypt Text
Information about encrypting text using the Cortex Encryptor.
Encrypt Text
To encrypt text using the Cortex Encryptor PowerShell module:
Extract the Cortex Innovation 2022.9 - Encryptor.zip file to a folder with the same name.
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Encryptor folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Encryptor"
In the Windows PowerShell (x64) window, run the following command to import the module:
Import-Module.\Cortex.Encryptor.psd1
In the Windows PowerShell (x64) window, run the following command to encrypt text, replacing text to encrypt with the text that you want to encrypt:
ConvertTo-EncryptedText-Text"text to encrypt"
The command will return the encrypted text, beginning with #_. This step can be repeated for any texts that need to be encrypted.
Note:
The Import-Module command will need to be repeated every time a new PowerShell window is used. To install the PowerShell module so that it is always available, follow the instructions laid out here.
3.1.1.3.6 - Port Requirements for Application Servers and Load Balancer
Information about the ports opened when installing Cortex Innovation.
Port Requirements for Application Servers and Load Balancer
Cortex Innovation and Microsoft Service Fabric open a range of firewall ports between the servers and specific services. Some of them are opened during installation, others are opened dynamically as needed. These are opened on Windows Firewall. If any other firewall exists between the servers, it will be necessary to configure this selection of rules on it. Most ports may be altered if another program overlaps with them, the description will say if this is not possible.
Cortex Innovation Ports
Name
Description
Default Port(s)
Protocol
Direction
Cortex.RabbitMqAmqpPorts
The port used by AMQP 0-9-1 and 1.0 clients with TLS. This cannot currently be changed.
5671
TCP
Inbound
Cortex.RabbitMqEpmdPorts
The port used by epmd, a peer discovery service used by RabbitMQ nodes and CLI tools. This cannot currently be changed.
4369
TCP
Inbound
Cortex.RabbitMqErlangDistribut ionClientPorts
The ports used by CLI tools (Erlang distribution client ports) for communication with nodes and is allocated from a dynamic range (computed as Erlang dist port + 10000 through dist port + 10010). This cannot currently be changed.
35672-35682
TCP
Inbound
Cortex.RabbitMqErlangDistribut ionServerPort
The port used for RabbitMQ inter-node and CLI tools communication (Erlang distribution server port) and is allocated from a dynamic range (limited to a single port by default, computed as AMQP port + 20000). This cannot currently be changed.
25672
TCP
Inbound
Cortex.RabbitMqManagement ApiPort
The port used by the RabbitMQ management plugin. This cannot currently be changed.
15671
TCP
Inbound
Cortex.WindowsSmbRemote Registry
The ports used by Windows SMB and Remote Registry service.
The port used by the applications and services deployed on a node to communicate with the Service Fabric client on that particular node.
8004
TCP
Inbound
Microsoft Service Fabric Firewall Rules (present on all Application Servers, with Domain, Public and Private Profiles)
These rules will all appear in Windows Firewall with names starting with ‘{CustomerName}.{NodeName} WindowsFabric’.
Name in Rule
Name in Config
Description
Default Port(s)
Protocol(s)
Direction
Application Processes
application Ports
The ports that are used by the Service Fabric applications. Service Fabric uses these ports whenever new dynamic ports are required. The application port range should be large enough to cater for the dynamic port allocation of the application. Currently at least 400 is recommended. This may change if new services are added. This range should not overlap the Dynamic Ports (ephemeralPorts) range as set in the configuration.
Program: Any
10010-10500
TCP, UDP
Inbound, Outbound
BackupRestore Service Process
N/A
The port used by the Service Fabric process which manages the backup and restore of Application Services.
The port used by the Service Fabric Diagnostics Collection Agent, which manages Diagnostic data.
Program: %ProgramFiles%\Microsoft Service Fabric\bin\ Fabric\DCA.Code\FabricDCA.exe
Any
TCP
Outbound
Dynamic Ports
ephemeral Ports
Override the dynamic ports used by the OS. Service Fabric uses a part of these ports as application ports, and the remaining are available for the OS. It also maps this range to the existing range present in the OS, so for all purposes, you can use the ranges given in the sample JSON files. Make sure that the difference between the start and the end ports is at least 255. You might run into conflicts if this difference is too low, because this range is shared with the OS. To see the configured dynamic port range, run netsh int ipv4 show dynamicport tcp.
Program: Any
10501-20000
TCP, UDP
Inbound, Outbound
EventStore Service Process
N/A
The port used by the Service Fabric EventStore, which maintains events about the state of the Application Services.
This port cannot be changed at the current time. If it is already in use, please contact Cortex for assistance. The reverse proxy endpoint. For more information, see Service Fabric reverse proxy.
Program: Any
9081
TCP
Inbound, Outbound
Http Gateway
http Gateway Endpoint Port
The port used by Service Fabric Explorer to connect to the cluster. This changes the port used to connect to the Service Fabric management portal as part of the post-install checks.
Program: Any
9080
TCP
Inbound, Outbound
Infrastructure Service Process
N/A
The port used by the Service Fabric Infrastructure Service.
Each service has an endpoint which is used to communicate with Service Fabric and the RabbitMQ message broker. These are configured in the ServiceManifest.xml file within each package in the ApplicationPackages\Cortex directory of the installation media. These ports cannot be used by any other program. If they do clash with another program, they may be changed but additional configuration changes may be necessary, as described in the description of each port. The Application ports must not lie in the ephemeralPorts range.
Name of Service
Description
Default Port(s)
Protocol(s)
Direction
Program
API Gateway
The port providing an entry into the API Gateway service. This is used by Cortex Gateway to communicate with the Application Services. If this is changed then it will be necessary to use the updated value in the"Service Fabric Api Gateway Endpoint" parameter of SetParameters.xml when configuring Cortex Gateway later in this document.
8722
TCP, UDP
Inbound, Outbound
Any
Flow Execution
The ports providing communication between other services and the stateful Cortex Flow Execution service. These are dynamic ports managed by Service Fabric.
Dynamic – Uses the application ports
N/A
N/A
N/A
Cortex Load Balancer Rules
Note
Only applicable for installations with HA.
The load balancer server must be able to retrieve traffic via HTTPS. The following firewall ports are opened by the installer (these rules will all appear in Windows Firewall with names starting with {CustomerName}):
Name in Rule
Name in Config
Default Port(s)
Protocol(s)
Direction
Program
GoBetweenTlsPort
loadBalancerTlsPort
443
TCP
Inbound
Any
3.1.1.3.7 - Rollover CA certificates
Information about updating the certificates on a single or multi-server Cortex platform which uses CA certificates.
Rollover CA certificates
This process MUST be undertaken before certificates expire, otherwise your system will become unusable. If certificates have already expired, contact Cortex Service Portal at the earliest opportunity.
Only platforms which use CA certificates can have their certificates updated using this mechanism. Systems using self-signed certificates must be reinstalled.
This mechanism cannot be used to switch from self-signed to CA certificates; that requires a reinstall.
Warning
Updating the certificates on a single-server system with no high availability will result in downtime while the upgrade takes place. Ensure that this is undertaken at a suitable time. Systems with high availability will use a rollover mechanism which should not result in any downtime.
Application Server
Prerequisites
Certificate Requirements
A new, valid X.509 certificate needs to be obtained to update the certificates.
The certificate can be obtained from a Certificate Authority, such as Let’s Encrypt, and must meet the following requirements:
Subject field must be in a wildcard format, pertaining to the domain of the Application Servers (e.g. CN=*.domain.com).
Subject alternative names must include any additional host names that should be able to be used to access the API Gateway Service.
Certificate file must be in a .PFX file format, with a known password.
Certificate file must contain the full chain of certificates.
Certificate file must include the private key.
Key Usage extension must have a value of Digital Signature, Key Encipherment (a0).
Enhanced Key Usage must include Server Authentication and Client Authentication.
This file should be placed in a known location on the Application Server where the certificate update script will be run. This location will be required when running the update script.
If required, a separate X.509 SSL certificate can be obtained to be used by the load balancer to communicate with the Application Services. It must meet all of the other requirements laid out above, except the subject field can also be the FQDN of the load balancer (e.g. CN=machine-name.domain.com).
Configure Update Certificates Script
In the Cortex Innovation 2022.9 - App Server Install Scripts folder, locate the Cortex.Innovation.Update.Certificates.ps1 script and open it with a text editor.
Choose the tab below that matches the configuration for this installation, then update the script to match, changing the parameters according to the details given below:
Securing communication between the Application Services.
Allowing Application Services to identify themselves to clients such as Gateway.
Preventing unauthorised nodes from joining the single node cluster.
Connecting to Service Fabric Explorer from each of the Application Servers.
ServerCertificatePwd
The password for the .PFX certificate file specified in ServerCertificatePath.
ClientCertificatePath
The local path of a .PFX certificate file on the first Application Server in the ApplicationServerIPv4Addresses list. This can be the same certificate as the ServerCertificatePath. Environment variables cannot be used.
This is only needed if installing with CA Certificates (Recommended) and using the Built-In Load Balancer. The certificate should meet the Certificate Requirements.
This certificate will be used for:
Securing communication between the load balancer and the nodes on the Application Servers.
ClientCertificatePwd
The password for the .PFX certificate file specified in ClientCertificatePath.
This is only needed if using the Built-In Load Balancer.
SkipLoadBalancer
Updates certificates without updating a load balancer.
Credential
The credentials of the user which will be used to perform remote operations on the server. It must be a domain user that is a member of the local Administrators group on the server.
This does not need to be changed, a prompt will appear to enter this information when the script is run.
Test Update Certificates Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Test Cortex.Innovation.Update.Certificates.ps1 by running the following command:
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on the server and press OK.
Wait for the command to finish. It will display the output of the certificate update command without making any changes to the system.
Check that there have been no errors in the script; these would appear in red in the console.
If there are no errors, continue to the next section; otherwise, check if the errors have any instructions for rectifying the issue and follow them.
If there are no useful instructions, check that all previous steps have been followed correctly and, if not, rectify it and run the command again.
If this does not work, please contact Cortex Service Portal for further assistance. The WhatIf script will have created a temporary version of the config file in the script location, showing what changes would be made to it when the script runs. The name is appended with -WhatIf (e.g. Cortex.Innovation.Install.Config-WhatIf.json). This file can be provided when obtaining support.
Run Update Certificates Script
Update the certificates for the Application Services and the required infrastructure by running the following command (Tee-Object will write output to both the PowerShell console and a log file, the FilePath value can be changed if required):
Import the certificate, used in the ServerCertificatePath parameter of the Configure Update Certificates Script section, to your Current User certificate store. This can be achieved by double clicking on the certificate .PFX file and following the wizard.
Open a web browser.
Navigate to https://server.domain.com:9080/Explorer, where server.domain.com is the fully qualified domain name of the server. Replace 9080 with new httpGatewayEndpointPort value if it was changed during configuration.
The screen should resemble that in the following figure:
Healthy Service Fabric Explorer Cluster
The status circles should be entirely green - this indicates that the node and all services and instances are healthy. Other status pages can be accessed by expanding items in the leftmost pane. Issues can be tracked down to the failing component by expanding items with warning triangles or error icons on.
If there is still a warning that the certificate is close to expiring, wait a few hours and refresh the page and it should go away. It can take some time for the certificate to rollover.
Web Application Server
If the Web Applications also use an expiring certificate, it will also need to be updated:
Import the Certificate
If using a single server and using the same certificates for both the Application Services and Web Applications, a new certificate will already be installed. Otherwise, follow the following instructions to import the new certificate for use with the Web Applications:
Put the new, valid certificate in .pfx format on the Web Application Server.
Double click on the certificate file to open the install certificate wizard.
Select Local Machine then click Next.
Click Next.
Enter the Export Password which the certificate was generated with then click Next.
Select Place all certificates in the following store.
Click Browse….
Select Personal, click OK then click Next.
Click Finish.
Apply the Certificate
Open Internet Information Services (IIS) Manager.
In the left-hand pane of Internet Information Service (IIS) Manager, expand the server node.
Right-click on the Site node (usually Cortex) which contains the Debugger and Gateway.
Click Edit Bindings...
Click on the https binding and click Edit....
Click the SSL Certificate Select... button and select the new certificate from the table. Click OK to close the dialog.
Click OK to close Edit Bindings dialog.
Click Close to close the Bindings dialog.
Open Gateway in a browser. Click the padlock icon next to the URL. The certificate displayed should be the updated one.
3.1.1.3.8 - SSL Best Practices
Information about the recommended security settings for Innovation servers.
SSL Best Practices
A collection of registry settings can be applied during installation to guarantee your server is only using the recommended encryption algorithms and TLS protocols:
Type
Name
Enabled
Ciphers
AES 128/128
✓
AES 256/256
✓
Triple DES 168
✓
DES 56/56
✕
NULL
✕
RC2 128/128
✕
RC2 40/128
✕
RC2 56/128
✕
RC4 128/128
✕
RC4 40/128
✕
RC4 56/128
✕
RC4 64/128
✕
Hashes
MD5
✕
SHA
✓
SHA256
✓
SHA384
✓
SHA512
✓
KeyExchangeAlgorithms
Diffie-Hellman
✓
ECDH
✓
PKCS
✓
Protocols
Multi-Protocol Unified Hello
✕
PCT 1.0
✕
SSL 2.0
✕
SSL 3.0
✕
TLS 1.0
✕
TLS 1.1
✕
TLS 1.2
✓
Cipher Suites
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
✓
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
✓
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
✕
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA25
✕
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
✕
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
✕
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
✕
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
✕
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
✕
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
✕
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
✕
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
✕
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
✕
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
✕
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
✕
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
✕
TLS_RSA_WITH_AES_256_GCM_SHA384
✕
TLS_RSA_WITH_AES_128_GCM_SHA256
✕
TLS_RSA_WITH_AES_256_CBC_SHA256
✕
TLS_RSA_WITH_AES_128_CBC_SHA256
✕
TLS_RSA_WITH_AES_256_CBC_SHA
✕
TLS_RSA_WITH_AES_128_CBC_SHA
✕
TLS_RSA_WITH_3DES_EDE_CBC_SHA
✕
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
✕
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
✕
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
✕
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
✕
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
✕
TLS_RSA_WITH_RC4_128_SHA
✕
TLS_RSA_WITH_RC4_128_MD5
✕
TLS_RSA_WITH_NULL_SHA256
✕
TLS_RSA_WITH_NULL_SHA
✕
TLS_PSK_WITH_AES_256_GCM_SHA384
✕
TLS_PSK_WITH_AES_128_GCM_SHA256
✕
TLS_PSK_WITH_AES_256_CBC_SHA384
✕
TLS_PSK_WITH_AES_128_CBC_SHA256
✕
TLS_PSK_WITH_NULL_SHA384
✕
TLS_PSK_WITH_NULL_SHA256
✕
Warning
Disabling specific TLS versions or specific Cipher Suites can have impact on Cortex components themselves as well as their communication capabilities with third party systems and services, e.g. Flow Debugger Service executing flows with blocks which communicate with 3rd parties via PowerShell or REST. All parties communicating together must support a shared protocol version and cipher suite, otherwise they will not be able to establish a secure communication link between each other.
3.1.2 - Add Innovation to a 7.2 Installation
Information about adding Cortex Innovation to an existing Cortex 7.2 platform.
Cortex Innovation can be deployed on-premise across multiple servers to provide improved scale and high availability (HA), or to a single server if scale and HA aren’t required.
3.1.2.1 - Multiple Server - With HA (Recommended)
Information about adding Cortex Innovation to Cortex 7.2 across multiple on-premise servers with high availability (HA), including: information about components, supported architectures, prerequisites and installation instructions.
Multiple server installations with HA are recommended for the following scenarios:
Production installations that are required to scale and support HA
3.1.2.1.1 - Architecture
Information about the recommended platform architecture, including component descriptions.
Web portal that hosts applications for creating automation solutions and managing their full life-cycle, including design, development, testing, deployment, monitoring, maintenance and ultimately end-of-life.
Application hosted in Cortex Gateway that provides the graphical, low-code environment for developing, testing, versioning, publishing and managing the full life-cycle of automation solutions.
Required
Web Application Server
Cortex Flow Debugger Service
Web application that allows flows to be debugged and executed. Used by Cortex Studio to debug flows and provide block information.
Required
Web Application Server
Cortex API Gateway Service
Application Service that routes client requests to the correct distributed Cortex services.
Required
Application Server
Cortex Flow Execution Service
Application Service that executes automation flows.
Required
Application Server
Cortex Block Packages
A set of files which contain the blocks that users can use to build flows. Used by the Cortex Flow Debugger Service and the Cortex Flow Execution Service.
Required
Web Application Server, Application Server
Cortex Gateway Databases
A set of databases created automatically by Gateway which are used for storing data related to user roles, flows, etc. Hopefully, we can remove the need for Gateway Databases in the next release.
Distributed systems platform that hosts the Cortex services where automation solutions are deployed to; provides scalable, reliable and manageable enterprise-grade High Availability (HA) using clustering.
Message broker used by the NServiceBus messaging platform to transport messages asynchronously between distributed Cortex services using publish/subscribe mechanism.
Windows Service Manager that hosts the gobetween load balancer application as a Windows Service.
Required
Load Balancer
Note
Cortex v7.2 component descriptions are not covered in this guide. See separate v7.2 documentation for more information.
Possible Architectures
Cortex Innovation and v7.2 can run side-by-side, allowing flows to be built and run for both of them from the same Gateway instance. They each require a different set of back-end components to be installed. Innovation can be added to a v7.2 installation by using the existing hardware containing v7.2 components, using new hardware or a combination of the two. The only components shared by both Innovation and v7.2 are Gateway and its databases.
The installation process is the same, regardless of which architecture is used; Recommended, Minimum or Alternative. The only difference is the Hardware Requirements, which will be greater for existing machines as they need more resources to run more components.
Recommended Architecture
The recommended architecture for adding Innovation to a v7.2 Dual Site, Dual Server system requires 8 servers in total; the 4 existing servers, plus 4 new servers:
2x Existing Application Servers for v7.2, one of these will also act as the Web Application Server for Innovation. For Innovation, the existing Gateway will be upgraded and a new Flow Debugger Service will be added.
2x Existing Database Servers, used for v7.2 and Gateway databases.
1x New Load Balancer Server for Innovation.
3x New Application Servers for Innovation.
8 Server, Recommended Architecture Diagram
.
Minimum Architecture
The minimum architecture requires only the 4 existing servers:
2x Application Servers for v7.2, each of these will also host one of the three Application Servers for Innovation.
1x Database Server for v7.2, which will also host the remaining Application Server for Innovation.
1x Database Server for v7.2, which will also host the Load Balancer for Innovation.
4 Server, Minimum Architecture Diagram
.
Alternative Architectures
Alternative architectures are possible; any of the Innovation server roles may be installed on any of the existing or new servers provided that the hardware is capable of running everything according to the Hardware Requirements for Alternative Architectures. For example, if the database servers cannot have anything else installed on them, new servers may be used for the load balancer and the third Innovation Application Server. Additionally, an existing, alternative load balancer may be used instead of the bundled one. The only caveat is that the load balancer must not be installed on the same machine as an Innovation Application Server as it cannot be used to send traffic to itself.
Information about the prerequisites required on each server type for installation.
Prerequisites
The prerequisites required for each server role (as described in Architecture) are laid out in this guide. These must be considered before undertaking installation.
Note
All server roles (e.g. Load Balancer, Application Server, Web Application Server) referenced in the rest of this guide will refer to Innovation server roles unless otherwise stated.
Hardware Requirements
Hardware requirements differ for each server role depending on whether it is being installed on new hardware or hardware which already contains v7.2 components. The minimum requirements for existing hardware will be greater than those for new hardware. The requirements for using the Recommended Architecture can be found here. Requirements for using the Minimum Architecture can be found here. This table is also provided to help calculate requirements for Alternative Architectures.
300+ Recommended 70 Minimum 5+ free on installation drive
Existing V7.2 Database Server + Innovation Application Server
1
4+ Recommended 4 Minimum
16+ Recommended 12 Minimum
300+ Recommended 100 Minimum 40+ free on %ProgramData% drive
Existing V7.2 Application Server + Innovation Application Server
1
4+ Recommended 4 Minimum
16+ Recommended 12 Minimum
120+ Recommended 100 Minimum 40+ free on %ProgramData% drive
Existing V7.2 Application Server with Gateway + Innovation Application Server + Upgrade to Innovation Web Application Server
1
4+ Recommended 4 Minimum
16+ Recommended 12 Minimum
120+ Recommended 100 Minimum 30+ free on installation drive 40+ free on %ProgramData% drive
Alternative Architectures
This table displays the additional resources required when adding an Innovation Server Role to an existing server using Alternative Architectures. It can be used to calculate how many additional resources are needed to install Innovation by adding the numbers in the table to fully utilised resource usage on a given server.
All servers must be on the same domain and cannot be domain controllers.
DNS Requirements
The installation requires IP to hostname resolution to be available. Please ensure that you have the appropriate pointer (PTR) records configured on the DNS server for all of your servers (Web, Application and Load Balancer).
Licensing Requirements
A valid Cortex licence file and Cortex Innovation with v7.2 feature identifier must be procured from Cortex. The feature identifier is a GUID which will be used when configuring the Gateway installation. The licence file is needed when installing the Web Application server and it should contain fingerprints for the Web Application Server and each Application Server.
To get a licence file and feature identifier take the following steps:
Copy the following template to a text file:
Web Application Server
MachineID:
Fingerprint:
Application Server 1
MachineID:
Fingerprint:
Application Server 2
MachineID:
Fingerprint:
Application Server 3
MachineID:
Fingerprint:
Please also include a suitable Cortex Innovation with v7.2 feature identifier.
From that folder, copy Cortex.Licensing.FingerprintGeneration.exe to the Web Application server.
Double-click Cortex.Licensing.FingerprintGeneration.exe to run it. A command line window will appear, containing a machine identifier and fingerprint, e.g:
Copy the output (machine identifier and fingerprint) to the Web Application Server section of the text file created in the initial step. Note that the machine identifier can be changed to any string, provided that it is different for each server.
For each Application Server take the following steps:
Copy Cortex.Licensing.FingerprintGeneration.exe to the Application server.
Double-click Cortex.Licensing.FingerprintGeneration.exe to run it. A command line window will appear, containing a machine identifier and fingerprint, e.g:
Copy the output (machine identifier and fingerprint) to one of the Application Server sections of the text file created in the initial step. Note that the machine identifier can be changed to any string, provided that it is different for each server.
Request a licence and feature identifier by raising a case in the Cortex Service Portal, including the contents of the text file containing all of the fingerprint and machine information in the body of the case.
When the licence and feature identifier have arrived, copy the file Cortex.lic to %ProgramData%\Cortex\Licences on the Web Application Server, creating the Cortex and Licences folders if they don’t exist. Save the feature identifier for use when Upgrading Gateway.
Web Browser Requirements
Gateway supports the latest versions of the following browsers:
Chrome
Edge
Firefox
Additional Load Balancer Server Requirements
Filesystem Requirements
If using the included gobetween load balancer, Network Discovery and File Sharing must be enabled on the Load Balancer Server:
Open File Explorer.
Click Network on the left.
A banner similar to the following will appear if Network Discovery and File Sharing is turned off:
Network and File Discovery Disabled
Click the banner.
Click Turn on network discovery and file sharing:
Enable Network and File Discovery
Alternative Load Balancer Requirements
Innovation has a gobetween load balancer included that isn’t highly available; It is possible to use an alternative. The requirements for installing an alternative load balancer are as follows:
Must support a round robin (or similar) method of load balancing to specified ports on 3 nodes.
Must be able to health check each node by running a predefined batch script (ApiGatewayTypeHealthcheck.bat, which resides in the gobetween folder of the Cortex Innovation 2022.9 - App Server Install Scripts) that returns 1 for healthy and 0 for unhealthy.
Must be able to access each of the Application Servers via HTTPS.
Ideally it should be highly available to avoid a single point of failure in the system.
Additional Application Server Requirements
Filesystem Requirements
All Application Servers must use an NTFS filesystem.
Network Discovery and File Sharing should be enabled on each Application Server:
Open File Explorer.
Click Network on the left.
A banner similar to the following will appear if Network Discovery and File Sharing is turned off:
Network and File Discovery Disabled
Click the banner.
Click Turn on network discovery and file sharing:
Enable Network and File Discovery
Service Requirements
The following Windows Services must be running on all Application Servers:
Remote Registry
Windows Event Log
Performance Logs & Alerts
Security Requirements
Installation User
A domain user which is a member of the Local Administrators group on all Application Servers and Load Balancer Server must be available to run the installation scripts. This is a prerequisite of Microsoft Service Fabric, which is the HA platform that Cortex Innovation is built upon.
Antivirus Exclusions
It is advised (by Microsoft Service Fabric) that the following antivirus exclusions are created on each Application Server to reduce antivirus processing on Service Fabric artefacts:
Folder Exclusions:
%ProgramFiles%\Microsoft Service Fabric
%ProgramData%\SF
%ProgramData%\SF\Logs
Process Exclusions:
Fabric.exe
FabricHost.exe
FabricInstallerService.exe
FabricSetup.exe
FabricDeployer.exe
ImageBuilder.exe
FabricGateway.exe
FabricDCA.exe
FabricFAS.exe
FabricUOS.exe
FabricRM.exe
FileStoreService.exe
A script is provided during installation to add these exclusions for Windows Defender. If any other antivirus software is running, these will need to be added manually.
If adding the exclusions manually, the Process Exclusions should be done before installation occurs, as the processes will be used during installation of the application and antivirus software can cause the installation to fail or timeout. Folder Exclusions may need to be added after installation has occurred as some antivirus software needs the folders to exist.
Port Requirements
Cortex Innovation and Microsoft Service Fabric require a range of firewall ports to be opened between the servers and specific services.
If you are using Windows Firewall, some ports are opened during installation and others are opened dynamically as needed. If any other firewall is used, it will be necessary to add the rules described in Port Requirements to open the correct ports.
The Cortex.Innovation.Test.PortUsage.ps1 script is provided during installation to test the ports on each Application Server and make sure they do not overlap with any other programs; most ports may be altered if this is the case, the description will say if this is not possible.
Certificate Requirements
Note
For production systems it is recommended that X.509 SSL wildcard certificates are obtained from a Certificate Authority and used for installation. For non-production systems, certificates can be omitted from installation and it will create and use self-signed certificates. This may prevent 3rd parties that require valid certificate verification to access the API Gateway Service.
An X.509 SSL wildcard certificate should be used to:
Secure communication between the load balancer and the nodes on the Application Servers.
Secure communication between the Application Services.
Allow Application Services to identify themselves to clients such as Gateway.
Prevent unauthorised nodes from joining the HA cluster.
Connect to Service Fabric Explorer from each of the Application Servers.
The certificate can be obtained from a Certificate Authority, such as Let’s Encrypt, and must meet the following requirements:
Subject field must be in a wildcard format, pertaining to the domain of the Application Servers (e.g. CN=*.domain.com).
Subject alternative names must include any additional host names that should be able to be used to access the API Gateway Service.
Certificate file must be in a .PFX file format, with a known password.
Certificate file must contain the full chain of certificates.
Certificate file must include the private key.
Key Usage extension must have a value of Digital Signature, Key Encipherment (a0).
Enhanced Key Usage must include Server Authentication and Client Authentication.
This file should be placed in a known location on the Application Server where the installation scripts will be run. This location will be required when running the installation script.
If required, a separate X.509 SSL certificate can be obtained to be used by the load balancer to communicate with the Application Services. It must meet all of the other requirements laid out above, except the subject field can also be the FQDN of the load balancer (e.g. CN=machine-name.domain.com).
TLS Requirements
There is a set of non-compulsory security measures, recommended to be applied to the Application Servers, in order to prevent potential attacks that exploit known industry security vulnerabilities. This includes disabling all versions of SSL and TLS apart from TLS 1.2. And disabling all cipher suites apart from the following:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
See SSL Best Practices for a full list of the security changes which will be applied. The Cortex.Innovation.Install.Multiple.SSLBestPractices.ps1 script is provided during installation to apply these security changes to the Application Servers.
Additional Web Application Server Requirements
Security Requirements
Installation User
Domain users must be available to run the Application Pools for Gateway and Flow Debugger Service. These users must be given Log on as a service and Log on as a batch job permissions otherwise the Application Pools will not be able to run. Information about how to do this will be given during installation.
For Flow Debugger Service, the NETWORK SERVICE user can also be used.
Domain Requirements
For Gateway, only Windows domains with an Active Directory domain controller running Active Directory Domain Services are supported.
Supported versions of Active Directory are listed below:
Version
Verified?
Supported From
Supported Until
Windows Server 2003
✓
Cortex v2022.9
To be evaluated
Windows Server 2003 R2
Cortex v2022.9
To be evaluated
Windows Server 2008
Cortex v2022.9
To be evaluated
Windows Server 2008 R2
✓
Cortex v2022.9
To be evaluated
Windows Server 2012
Cortex v2022.9
To be evaluated
Windows Server 2012 R2
✓
Cortex v2022.9
To be evaluated
Windows Server 2016
✓
Cortex v2022.9
To be evaluated
Windows Server 2019
Cortex v2022.9
To be evaluated
Windows Server 2022
Cortex v2022.9
To be evaluated
Certificate Requirements
Both Gateway and the Flow Debugger Service require an X.509 SSL certificate to be installed on the Web Application Server. The certificate must have the following properties:
Enhanced Key Usage: Server Authentication and Client Authentication
Subject Alternative Names (SAN): At minimum the FQDN of the Server. It can also include NetBIOS Name, IP address, localhost, 127.0.0.1
If the user tries to navigate to an address not in the SAN list, then they will receive a certificate error.
Wildcard certificates and self-signed certificates can also be used. However, self-signed certificates are not recommended for production instances. Details on how to create a self-signed certificate can be found at Create Self-Signed Certificates.
The certificate may be the same one used for the Application Server installation.
More information about importing the certificate is given during installation.
TLS Requirements
There is a set of non-compulsory security measures, recommended to be applied to the Web Application Server, in order to prevent potential attacks that exploit known industry security vulnerabilities. This includes disabling all versions of SSL and TLS apart from TLS 1.2. And disabling all cipher suites apart from the following:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
See SSL Best Practices for a full list of the security changes which will be applied. The Cortex.Innovation.Install.SSLBestPractices.ps1 script is provided during installation to apply these security changes to the Web Application Server.
Next Steps?
Application Servers and Load Balancer server are installed in the same way regardless of whether new or existing hardware is being used:
A software-based load balancer called gobetween is provided with the platform. This must be installed on its own server as it doesn’t support routing traffic to itself. It also doesn’t currently support HA, but it may be possible to use multiple gobetween load balancers with Anycast network addressing and routing to provide high availability, as described in https://en.wikipedia.org/wiki/Anycast; however, this has not been verified yet. It is possible to use an alternative load balancer to the one provided. ↩︎↩︎
Application Servers support HA via clustering. A cluster must consist of a minimum of 3 nodes, and the number of nodes must be an odd number to ensure a quorum. Currently only the Bronze availability (3 nodes) is supported. Silver, Gold and Platinum support will be added in future. ↩︎
Windows Server Standard and Datacenter editions are supported. Filesystem must be NTFS and networking must use IPv4. Linux is not supported, but may be in the future. ↩︎
SQL Server Express, Standard and Enterprise are supported. Other databases are not supported. Note that Transparent Data Encryption is not supported on SQL Server Express. ↩︎
PowerShell 5.1 ships with Windows Server 2016 and 2019. ↩︎
IIS is supported; other web servers, including IIS Express are not supported. ↩︎
Ships as a windows role within Windows Server 2019. ↩︎
Ships as a windows role within Windows Server 2016. ↩︎
3.1.2.1.3 - Install Application Servers and Load Balancer
Information about installing the Application Servers and Load Balancer Server.
Install Application Servers and Load Balancer
This guide describes how to install the Application Servers and Load Balancer Server. Please ensure that Prerequisites for adding Innovation to v7.2 have been read before starting this installation.
Make Installation Artefacts Available
Choose one of the Application Servers to be used for installation, and copy the following artefacts to a folder on it (the version numbers may differ):
Cortex Innovation 2022.9 - Block Packages.zip
Cortex Innovation 2022.9 - App Services.zip
Cortex Innovation 2022.9 - App Server Install Scripts.zip
Extract the Cortex Innovation 2022.9 - App Server Install Scripts.zip file to a folder with the same name.
Install Microsoft .NET Framework 4.7.1
Microsoft Service Fabric requires a minimum of Microsoft .NET Framework 4.7.1 to be installed on each Application Server.
To find the version of the framework that is installed:
On the Start menu, choose Run.
In the open box, enter regedit.exe. You must have administrative credentials to run regedit.exe.
In the Registry Editor, open the subkey HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full.
If the Full subkey is not present, then you do not have the .NET Framework 4.5 or later installed.
Check for a DWORD value named Release. The existence of the Release DWORD indicates the .NET Framework 4.5 or newer has been installed on that computer. If the value is 461308 or over then at least .NET Framework 4.7.1 is installed and no further steps need to be taken. If it is not installed, continue with the following steps to install it.
These are non-compulsory security measures, recommended to be applied to Application Servers and the Load Balancer Server, in order to prevent potential attacks that exploit known industry security vulnerabilities.
Applying these measures may impact other applications running on your servers. Therefore, it is your responsibility to ensure that other applications and their clients will not be affected by the changes.
Only Use Recommended Encryption Algorithms and TLS Protocols
A collection of registry settings need to be applied to guarantee your server is only using the recommended encryption algorithms and TLS protocols. Information about these settings can be found at SSL Best Practices.
Warning
Disabling specific TLS versions or specific Cipher Suites can have impact on Cortex components themselves as well as their communication capabilities with third party systems and services, e.g. Flow Debugger Service executing flows with blocks which communicate with 3rd parties via PowerShell or REST. All parties communicating together must support a shared protocol version and cipher suite, otherwise they will not be able to establish a secure communication link between each other.
The settings can be applied by running a script. Be aware that each server will be restarted when the script is run. Apply the settings by following these instructions:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Install.Multiple.SSLBestPractices.ps1 script using the following command, modifying the ApplicationServers value to contain the NETBIOS names or fully qualified domain names of the Application Servers and the LoadBalancerServer value to contain the NETBIOS names or fully qualified domain name of the Load Balancer Server (remove the LoadBalancerServer parameter if using an alternative load balancer):
To avoid answering all of the prompts -Override 0 can be added to the end of the script. This will automatically apply all settings and forcibly restart the servers.
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all servers (Application and Load Balancer) and press OK.
If -Override 0 has been specified no further steps need to be taken and you can move on to the next section when the servers have restarted.
To use all the recommended settings click Apply all to the each Apply Cortex recommended security best practices prompt.
To selectively apply each setting select Choose which to apply. Each change will then be prompted with a Yes/No confirmation before applying. This will need to be done for each server.
Restart each machine when the script asks. The current machine will be restarted last, the PowerShell script will close at this time.
Add Antivirus Exclusions
If Windows Defender is not running on the Application Servers, ensure that the Antivirus Exclusions have been added to the running antivirus software on each of the Application Servers and continue to the next section, otherwise follow these steps:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Add.WindowsDefenderExclusions.ps1 script using the following command, modifying the ApplicationServers value to contain the NETBIOS names or fully qualified domain names of the Application Servers:
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all Application Servers and press OK.
A message will indicate that the script has completed successfully.
Check Port Usage
To check all necessary ports are free, follow these steps.
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Test.PortUsage.ps1 script using the following command, modifying the ApplicationServers value to contain the NETBIOS names or fully qualified domain names of the Application Servers:
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all Application Servers and press OK.
If all ports are free, the script will report the following for each Application Server:
All ports required by Cortex Innovation are free
If this is the case, continue to the next section. Otherwise, consult the messages returned by the script, which will give details about how to modify the Cortex.Innovation.Install.Config.json configuration file, in the Cortex Innovation 2022.9 - App Server Install Scripts folder, to use different ports. This will be used later during installation.
The Cortex.Innovation.Test.PortUsage.ps1 script cannot currently re-check modified ports in the configuration file so these need to be manually checked to see that they are free.
Configure Installation Script
In the Cortex Innovation 2022.9 - App Server Install Scripts folder, locate the Cortex.Innovation.Install.ps1 script and open it with a text editor.
Choose the tab below that matches the configuration for this installation, then update the script to match, changing the parameters according to the details given below:
Configure this value with the location of the Application Services zip file on the Application Server used for installation.
BlockPackagesPath
Configure this value with the location of the Block Packages zip file on the Application Server used for installation.
ApiGatewayBasicAuthUserName
Configure this value with the username that will be used for Basic Authentication when making HTTPS requests to the API Gateway Service (e.g. starting production flows).
For security reasons it is recommended that the default value BasicAuthUser should be changed.
Currently only Basic Authentication using a single user is supported, OAuth2 will be supported in a future release.
Configure this value with the password that will be used for Basic Authentication when making HTTPS requests to the API Gateway Service (e.g. starting production flows).
This password should be Cortex Encrypted. For security reasons it is recommended that the default value ADA9883B11BD4CDC908B8131B57944A4 should be changed.
A name identifying the platform being installed. This must have no spaces or symbols. It will be appended to the node names that are displayed in Service Fabric Explorer.
ApplicationServerIPv4Addresses
The IPv4 addresses of the Application Servers. The first of these must be the Application Server used for installation.
LoadBalancerServerIPv4Address
The IPv4 address of the Load Balancer Server. This is only needed if using the built-in load balancer.
ServerCertificatePath
The local path of a .PFX certificate file on the first Application Server in the ApplicationServerIPv4Addresses list. Environment variables cannot be used.
This is only needed if installing with CA Certificates (Recommended). The certificate should meet the Certificate Requirements.
This certificate will be used for:
Securing communication between the Application Services.
Allowing Application Services to identify themselves to clients such as Gateway.
Preventing unauthorised nodes from joining the HA cluster.
Connecting to Service Fabric Explorer from each of the Application Servers.
Warning
It is critical to set a reminder to update certificates in good time before they expire. If they expire then the platform will cease to function and Cortex Service Portal must be contacted for support.
ServerCertificatePwd
The password for the .PFX certificate file specified in ServerCertificatePath.
This is only needed if installing with CA Certificates (Recommended).
ClientCertificatePath
The local path of a .PFX certificate file on the first Application Server in the ApplicationServerIPv4Addresses list. This can be the same certificate as the ServerCertificatePath. Environment variables cannot be used.
This is only needed if installing with CA Certificates (Recommended) and using the Built-In Load Balancer. The certificate should meet the Certificate Requirements.
This certificate will be used for:
Securing communication between the load balancer and the nodes on the Application Servers.
Warning
It is critical to set a reminder to update certificates in good time before they expire. If they expire then the platform will cease to function and Cortex Service Portal must be contacted for support.
ClientCertificatePwd
The password for the .PFX certificate file specified in ClientCertificatePath.
This is only needed if installing with CA Certificates (Recommended) and using the Built-In Load Balancer.
UseSelfSignedCertificates
Installs Application Services and required infrastructure using generated Self-Signed Certificates rather than CA Certificates.
Not recommended for production use.
SkipLoadBalancer
Installs Application Services and required infrastructure without installing a load balancer. Use when using an alternative load balancer or no load balancer.
Credential
The credentials of the user which will be used to perform remote operations on the Application Servers. It must be a domain user that is a member of the local Administrators group on all servers.
This does not need to be changed, a prompt will appear to enter this information when the script is run.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
More advanced configuration (such as changing ports) can be undertaken by modifying the Cortex.Innovation.Install.Config.json file but this shouldn’t be required for most installations. More information about this can be found at Advanced Application Server and Load Balancer Configuration Changes.
Save and close Cortex.Innovation.Install.ps1.
Test Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Type the following command into PowerShell:
.\Cortex.Innovation.Install.ps1-WhatIf
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to test the installation script.
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all servers (Application and Load Balancer) and press OK.
A password prompt will appear. Enter a password which will be used to create a user in RabbitMQ.
Wait for the command to finish. It will display the output of the installation command without making any changes to the system, to ensure things like communication between the servers are working.
Check that there have been no errors in the script; these would appear in red in the console.
If there are no errors, continue to the next section; otherwise, check if the errors have any instructions for rectifying the issue and follow them.
If there are no useful instructions, check that all previous steps have been followed correctly and, if not, rectify it and run the command again.
If this does not work, please contact Cortex Service Portal for further assistance. The WhatIf script will have created a temporary version of the config file in the script location, showing what changes would be made to it when the script runs. The name is appended with -WhatIf (e.g. Cortex.Innovation.Install.Config-WhatIf.json). This file can be provided when obtaining support.
Run Installation Script
Type the following command into PowerShell:
.\Cortex.Innovation.Install.ps1
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install HA Services and the required infrastructure.
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all servers (Application and Load Balancer) and press OK.
A password prompt will appear. Enter a password which will be used to create a user in RabbitMQ. This should be entered carefully and recorded as it may be needed if seeking support from Cortex Service Portal. Press OK.
Wait for the script to finish running. This should take approximately 10 minutes.
Check that there have been no errors in the script; these would appear in red in the console.
If there are any errors, then please follow any instructions given within them to rectify the situation, check your configuration files, and retry the installation.
In some circumstances, retrying may error due to components being installed already. In this case please run the following command, followed by the original installation command:
Import the client certificate, used in the ClientCertificatePath parameter of the Configure Installation Script section, to your Current User certificate store. This can be achieved by double clicking on the client certificate .PFX file and following the wizard.
If using self-signed certificates, the certificate can be retrieved by using the Manage Computer Certificates tool in Windows to export the CortexServerCertificate from the Personal store and then importing it to the Current User store by double-clicking on it and following the wizard.
Open a web browser.
Navigate to https://app-server.domain.com:9080/Explorer, where app-server.domain.com is the fully qualified domain name of any Application Server. Replace 9080 with new httpGatewayEndpointPort value if it was changed during configuration.
The screen should resemble that in the following figure:
Healthy Service Fabric Explorer Cluster
The status circles should be entirely green - this indicates that all nodes, services and instances are healthy. Other status pages can be accessed by expanding items in the leftmost pane. Issues can be tracked down to the failing component by expanding items with warning triangles or error icons on. The next few diagrams show the status pages for a healthy system.
After expanding the application, clicking on any of the services should display a green circle and Status = Active:
Healthy Service Fabric Explorer Service
After expanding either of the services, clicking on any of the instances/partitions should display a green circle and Status = Ready:
Healthy Service Fabric Explorer Instance
Clicking on any of the nodes at the bottom of the leftmost pane should display a green circle and Status = Up:
Healthy Service Fabric Explorer Node
If any warning triangles appear, wait for 5 minutes or so as the cluster may still be starting up. If the cluster looks OK, go to the next section.
If the warnings persist or anything on the screen goes red, expand the items to find the individual services and instances which have errors or warnings. Warnings should not be ignored as they can indicate that the service can’t start but is still in the retry phase. Error and warning messages should be displayed on the status screens and should indicate what is wrong.
If no useful message can be seen here, the service log files may contain more information. These can be found on each Application Server at:
%ProgramData%/Cortex/Cortex API Gateway Service
%ProgramData%/Cortex/Cortex Flow Execution Service
If no solution can be found, please contact Cortex Service Portal for further assistance.
Preserve installation files
Ensure that the installation files are backed up or kept on the server, especially the scripts and config files that have been modified. This will make it easier to perform further actions in future, such as troubleshooting, certificate rollover, uninstallation, reinstallation and updates.
3.1.2.1.4 - Upgrade v7.2 Gateway to Include Innovation
Information about upgrading v7.2 Gateway with Innovation functionality.
Upgrade v7.2 Gateway to Include Innovation
This guide describes how to upgrade Gateway on v7.2 to include Innovation. Please ensure that Install Application Servers and Load Balancer has been completed before starting this installation. These steps assume that the v7.2 version of Gateway and its prerequisites have already been installed.
The steps to add Innovation functionality to v7.2 are:
Install Flow Debugger Service
Upgrade Gateway
Make Installation Artefacts Available
We recommend that the Flow Debugger Service and Gateway are installed on the same Web Application Server. Copy the following artefacts to a folder on the machine (the version numbers may differ):
Cortex Innovation 2022.9 - Web App Server Install Scripts.zip
Extract the Cortex Innovation 2022.9 - Web App Server Install Scripts.zip zip file to a folder with the same name.
Install Prerequisites
Licensing
Ensure that a valid Cortex licence file named Cortex.lic exists on the Web Application server, in the location %ProgramData%\Cortex\Licences. If it does not, follow the instructions located at Licensing Requirements.
Install Flow Debugger Service
Get Application Pool User
A domain user account is required for the Flow Debugger Service web application pool and must be created prior to performing the installation. In line with best practices, this account should not be used for any purposes other than those specified for the Flow Debugger Service. Alternatively, the NETWORK SERVICE user may also be used.
This user must currently have access to the default NuGet directory, in order to load block packages correctly. To add permissions for the user take the following steps:
Navigate to %SystemRoot%\System32\config\systemprofile\AppData\Roaming\ and create a new folder named NuGet if one does not exist.
Right-click on the NuGet folder and click Properties.
In the dialog, click the Security tab.
Click the Edit... button.
Click the Add... button.
Enter the username of the application pool user and click OK.
In the Permissions section at the bottom, check Full control
Click OK.
The user must be given Log on as a service and Log on as a batch job permissions. To do this take the following steps:
Navigate to Start -> Administrative Tools -> Local Security Policy.
In the Local Security Policy dialog, expand the Local Policies node then select User Rights Assignment.
Take the following steps for the Log on as a service and Log on as a batch job policies:
In the right-hand panel, double-click on the policy.
In the Properties dialog, click on the Add User or Group button.
Note
It is possible to use the Advanced… button to look up names rather than entering them manually. Various filters can be set to find the correct user or group more easily. Multiple users can be selected by holding down CTRL while clicking. OK adds the selected users or groups into the Enter the object names to select text box.
Type the name of the application pool user account into the Enter the object names to select text box. Click the Check Names button to confirm that the user exists.
Click OK on the Select Users dialog, and then confirm the user is correct by clicking OK on the Properties dialog.
Configure Installation Script
In the Cortex Innovation 2022.9 - Web App Server Install Scripts folder, locate the Cortex.Innovation.Install.FlowDebuggerService.ps1 script and open it with a text editor.
Choose the tab below that matches the configuration for this installation, then update the script to match, changing the parameters according to the details given below:
Configure this value with the password that will be used for Basic Authentication when Gateway makes HTTPS requests to the Flow Debugger Service.
This password should be Cortex Encrypted. For security reasons it is recommended that the default value ADA9883B11BD4CDC908B8131B57944A4 should be changed.
Enables Flow Debugger Service to communicate with Gateway using generated Self-Signed Certificates rather than CA Certificates.
Not recommended for production use.
Credential
The credentials of the user that will be used to run the Debugger application pool in IIS.
This does not need to be changed, a prompt will appear to enter this information when the script is run.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
Save and close Cortex.Innovation.Install.FlowDebuggerService.ps1.
Run Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Web App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Web App Server Install Scripts"
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install the Flow Debugger Service.
A credentials prompt will appear. Enter the credentials of the user that should run the Debugger application pool in IIS. If using the NETWORK SERVICE user, enter any user as the username and leave the password blank; the NETWORK SERVICE user will need to be selected in the final step.
Wait for the script to finish running. This should take approximately 2 minutes.
An error may have appeared saying:
The Windows Process Activation Service service is not started.
This can be ignored.
Check that there have been no other errors in the script; these would appear in red in the console.
If there are any errors, then please follow any instructions given within them to rectify the situation, and retry the installation.
If the errors do not give any instructions on how to rectify, please contact Cortex Service Portal for further assistance.
If using NETWORK SERVICE for the application pool user:
Open Internet Information Services (IIS) Manager.
On the left, expand the server node.
Click Application Pools.
Right-click on the Debugger application pool and select Advanced Settings....
In the Advanced Settings dialog, click on Identity and then click the ellipses (...).
In the Application Pool Identity dialog, select Built-in account, then select NetworkService from the drop-down, then click OK.
Right-click on the Debugger application pool and click Recycle....
Upgrade Gateway
Configure Installation Script
In the Cortex Innovation 2022.9 - Web App Server Install Scripts folder, locate the Cortex.Innovation.Install.Gateway.ps1 script and open it with a text editor.
Configure the script according to the details given below:
Configure this value with the location of the Cortex Innovation 2022.9 - Gateway.zip file on the installation server.
GatewayApplicationIISPath
Change to the correct Site Name/Application if either was modified from the defaults (Cortex/gateway) when creating the website or application.
FeatureFlags
Replace InnovationId with the Cortex Innovation feature identifier, which should have been provided by Cortex when fulfilling the Licensing Requirements, if it wasn’t it should be requested using Cortex Service Portal.
This will overwrite the FeatureFlags value in the Gateway web.config.
ServiceFabricApiGatewayEndpoint
Replace server.domain.com with the fully qualified domain name of the Load Balancer Server. The port should be specified if it is not the default HTTPS port (443), and there must be a trailing slash, e.g. https://server.domain.com/ or https://server.domain.com:8722/.
This will overwrite the ServiceFabricApiGatewayEndpoint value in the Gateway web.config.
ServiceFabricUsingSelfSignedCertificates
Configure the value as $false if you used valid CA certificates when installing the Application Servers, $true if you used self-signed certificates.
This will overwrite the ServiceFabricUsingSelfSignedCertificates value in the Gateway web.config.
ServiceFabricApiGatewayBasicAuthUsername
This must be changed if you used a non-default ApiGatewayBasicAuthUserName when installing the Application Servers; if so, this value must be configured to the one used.
This will overwrite the ServiceFabricApiGatewayBasicAuthUsername value in the Gateway web.config.
This will overwrite the ServiceFabricApiGatewayBasicAuthPassword value in the Gateway web.config.
DotNetFlowDebuggerEndpoint
Replace server.domain.com with the fully qualified domain name of the Web Application Server.
This will overwrite the DotNetFlowDebuggerEndpoint value in the Gateway web.config.
DotNetFlowDebuggerBasicAuthUsername
This must be changed if you used a non-default FlowDebuggerBasicAuthUserName when installing the Flow Debugger Service; if so, this value must be configured to the one used.
This will overwrite the DotNetFlowDebuggerBasicAuthUsername value in the Gateway web.config.
This will overwrite the DotNetFlowDebuggerBasicAuthPassword value in the Gateway web.config.
DotNetFlowDebuggerUsingSelfSignedCertificates
Configure the value as $false if you are using valid CA certificates to secure the site containing Gateway and Flow Debugger Service, $true if using self-signed certificates.
This will overwrite the DotNetFlowDebuggerUsingSelfSignedCertificates value in the Gateway web.config.
Test
This does not need to be changed, it will be set at a later stage.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
Save and close Cortex.Innovation.Install.Gateway.ps1.
Test Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Web App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Web App Server Install Scripts"
Type the following command into PowerShell:
.\Cortex.Innovation.Install.Gateway.ps1-Test
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to test the configuration.
In the event of any errors, there will be an error message displayed at the end of the output with a line confirming the Error Count.
Run Installation Script
Ensure the Gateway application pool is stopped:
Open Internet Information Service (IIS) Manager.
In the left pane, expand the server node.
Click Application Pools to display a list of the Application Pools.
Right-click the Cortex Gateway application pool and select Stop.
Note
Failure to stop the application pool will result in a permissions error when installing Gateway.
Type the following command into PowerShell:
.\Cortex.Innovation.Install.Gateway.ps1
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install Gateway.
In the event of any errors, there will be an error message displayed at the end of the output with a line confirming the Error Count.
Start the Gateway application pool:
Open Internet Information Service (IIS) Manager.
In the left pane, expand the server node.
Click Application Pools to display a list of the Application Pools.
Right-click the Cortex Gateway application pool and select Start.
Once the application pool has been started, the site will be available on <protocol>://<host>:<port>/<webapplicationname>, e.g. https://localhost/gateway.
Note
If the application pool does not stay started, ensure that the user it runs as has Log on as a service and Log on as a batch job permissions or belongs to a group that has those permissions.
Information about trying out Cortex Innovation for the first time.
Try it out
This guide describes how to try out a new Innovation installation to make sure it is working.
Test Debugging Flows
Test the platform by creating a new flow and executing it using the following steps:
Click on the Flows charm, then the + button and click Group to open a dialog.
Enter a name for the group, configure the Permission Groups and click OK to create the group.
Click on the group to open it (refresh the page if it does not appear).
Inside the group, click the + button again and click on Flow(Innovation) to open a dialog. If the menu item is not present, it means that the FeatureFlags in the CortexGateway.SetParameters.xml file was not set properly when installing Gateway. See Troubleshooting for more information.
Enter a name for the flow, configure the Permission Groups and click OK to create the flow.
The flow should be displayed with a start flow block and end flow block. A list of block palettes should be displayed down the left hand side:
New Flow - Number of palettes may differ
If the blocks in the flow do not display or the palettes are not visible, see Troubleshooting for more information.
Add a Set Variable block and connect it between the start and end blocks.
Click the Set Variable block to open the Property Editor.
Set the Value property to the expression DateTimeOffset.Now.
Type Result into the Variable property and click Create Result.
In the Variable Editor, set Is Output Variable? to true for the new Result variable.
Set a breakpoint on the end block and start the flow. An execution token should appear, the Result variable should show the current time. If the token does not appear, try refreshing the page.
Continue or stop the execution.
Commit the flow.
Test Publishing Production Flows
Log in to Gateway with a user that has the Admin role.
Click on the Settings charm, then Packages.
Click Add Package Definition. Enter a package name and select the new flow to add to the package. Click Save to save the new package.
Click Publish. A success message should appear. If it doesn’t it means that either one or more of the parameters prefixed with Service Fabric in the CortexGateway.SetParameters.xml file was not set properly when updating Gateway, or the Application Services aren’t healthy. See Troubleshooting for more information.
Test Executing Production Flows
Open an HTTP client, such as Postman. Make a request with the following format:
Property
Value
Action
POST
URL
https://{FQDN of Load Balancer Server}/api/default/default/flows/{Flow Name}/executions?packageName={Package Name} e.g. https://load-balancer.domain.com/api/default/default/flows/NewFlow/executions?packageName=NewPackage
Content Type
application/json
Body
{}
Authentication
Basic
Username
The value used for ApiGatewayBasicAuthUserName when installing Application Services
Password
The value used for ApiGatewayBasicAuthPwd when installing Application Services (Unencrypted)
Note
If you used self-signed certificates when installing the Application Servers you will need to disable SSL certificate validation in your HTTP client.
The request should return a JSON object with the output variables of the flow e.g. { "Output": "2022-03-09T07:35:16+0000" }.
Cortex Innovation has now been verified and is ready to use.
3.1.2.2 - Single Server - Without HA
Information about adding Cortex Innovation to Cortex 7.2 on a single on-premise server without high availability (HA), including: information about components, supported architectures, prerequisites and installation instructions.
Single server installations with HA are not recommended for the following scenarios:
Production installations that are required to scale and support HA
3.1.2.2.1 - Architecture
Information about the recommended Innovation platform architecture, including component descriptions.
Web portal that hosts applications for creating automation solutions and managing their full life-cycle, including design, development, testing, deployment, monitoring, maintenance and ultimately end-of-life.
Application hosted in Cortex Gateway that provides the graphical, low-code environment for developing, testing, versioning, publishing and managing the full life-cycle of automation solutions.
Required
Web Application Server
Cortex Flow Debugger Service
Web application that allows flows to be debugged and executed. Used by Cortex Studio to debug flows and provide block information.
Required
Web Application Server
Cortex API Gateway Service
Application Service that routes client requests to the correct Application Services.
Required
Application Server
Cortex Flow Execution Service
Application Service that executes automation flows.
Required
Application Server
Cortex Block Packages
A set of files which contain the blocks that users can use to build flows. Used by the Cortex Flow Debugger Service and the Cortex Flow Execution Service.
Required
Web Application Server, Application Server
Cortex Gateway Databases
A set of databases created automatically by Gateway which are used for storing data related to user roles, flows, etc. Hopefully, we can remove the need for Gateway Databases in the next release.
Message broker used by the NServiceBus messaging platform to transport messages asynchronously between Application Services using publish/subscribe mechanism.
Erlang run-time required by the RabbitMQ message broker.
Required
Application Server
Single Server Architecture
Cortex Innovation and v7.2 can run side-by-side, allowing flows to be built and run for both of them from the same Gateway instance. They each require a different set of back-end components to be installed. Innovation can be added to a Cortex v7.2 installation by using the existing hardware. The only components shared by both Innovation and v7.2 are Gateway and its databases.
The minimum architecture for adding Innovation to a v7.2 Single Site, Single Server system is as follows:
1 Server Architecture Diagram
Warning
This architecture is not recommended for production platforms that are required to scale and support HA. Additionally, upgrades require application redeployment with downtime rather than using rolling upgrades.
Information about the prerequisites required on each server type for installation.
Prerequisites
The prerequisites required for a single server (as described in Architecture) are laid out in this guide. These must be considered before undertaking installation.
Hardware Requirements
Note
This configuration is not recommended for production servers that are required to scale and support HA.
Server Role
Servers Required
CPU Cores (> 2GHz)
RAM (GB)
Disk (GB)
Single Server Application Server + Web Application Server
1
4+ Recommended 4 Minimum
16+ Recommended 12 Minimum
160+ Recommended 135 Minimum 30+ free on installation drive 40+ free on %ProgramData% drive
The server must be on a domain and cannot be a domain controller.
DNS Requirements
The installation requires IP to hostname resolution to be available. Please ensure that you have the appropriate pointer (PTR) records configured on the DNS server for the server.
Licensing Requirements
A valid Cortex licence file and Cortex Innovation feature identifier must be procured from Cortex. The feature identifier is a GUID which will be used when configuring the Gateway installation. The licence file is needed when installing the server and it should contain that server’s fingerprint.
To get a licence file and feature identifier take the following steps:
Copy the following template to a text file:
Web Application/Application Server
MachineID:
Fingerprint:
Please also include a suitable Cortex Innovation feature identifier.
From that folder, copy Cortex.Licensing.FingerprintGeneration.exe to the server.
Double-click Cortex.Licensing.FingerprintGeneration.exe to run it. A command line window will appear, containing a machine identifier and fingerprint, e.g:
MachineID: SERVER
Fingerprint: 111118BA104C928319E0CBAE30844CF8B7FD8BC414D1567844D1D0830089F1C9BF5C6
Copy the output (machine identifier and fingerprint) to the Web Application/Application Server section of the text file created in the initial step. Note that the machine identifier can be changed to any string.
Request a licence and feature identifier by raising a case in the Cortex Service Portal, including the contents of the text file containing all of the fingerprint and machine information in the body of the case.
When the licence and feature identifier have arrived, copy the file Cortex.lic to %ProgramData%\Cortex\Licences on the Web Application Server, creating the Cortex and Licences folders if they don’t exist. Save the feature identifier for use when Upgrading Gateway.
Web Browser Requirements
Gateway supports the latest versions of the following browsers:
Chrome
Edge
Firefox
Certificate Requirements
Note
For production systems it is recommended that an X.509 SSL certificate is obtained from a Certificate Authority and used for installation. For non-production systems, certificates can be omitted from installation and it will create and use self-signed certificates. This may prevent 3rd parties that require valid certificate verification to access the API Gateway Service.
An X.509 SSL certificate (standard or wildcard) should be used to:
Allow Application Services to identify themselves to clients such as Gateway.
Prevent unauthorised nodes from joining the single node cluster.
Connect to Service Fabric Explorer from the Application Server.
Connect to Gateway.
Allow Gateway to connect to the Flow Debugger Service.
The certificate can be obtained from a Certificate Authority, such as Let’s Encrypt, and must meet the following requirements:
Subject field must be in one of the following formats, depending on the certificate type:
Standard certificates must use the standard format (e.g. CN=host.domain.com).
Wildcard certificates must use the wildcard format, pertaining to the domain of the server (e.g. CN=*.domain.com).
Subject alternative names must include any additional host names that should be able to be used to access the API Gateway Service.
Subject Alternative Names (SAN): At minimum the FQDN of the server. It can also include NetBIOS Name, IP address, localhost, 127.0.0.1. It must include any additional host names that should be able to be used to access the API Gateway Service.
Certificate file must be in a .PFX file format, with a known password.
Certificate file must contain the full chain of certificates.
Certificate file must include the private key.
Key Usage extension must have a value of Digital Signature, Key Encipherment (a0).
Enhanced Key Usage must include Server Authentication and Client Authentication.
This file should be placed in a known location on the server. This location will be required when running the Application Server installation script.
Warning
It is critical to set a reminder to update certificates in good time before they expire. If they expire then the platform will cease to function and Cortex Service Portal must be contacted for support.
TLS Requirements
There is a set of non-compulsory security measures, recommended to be applied to the server, in order to prevent potential attacks that exploit known industry security vulnerabilities. This includes disabling all versions of SSL and TLS apart from TLS 1.2, and disabling all cipher suites apart from the following:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
See SSL Best Practices for a full list of the security changes which will be applied. The Cortex.Innovation.Install.SSLBestPractices.ps1 script is provided during installation to apply these security changes to the server.
Additional Application Server Requirements
Filesystem Requirements
The server must use an NTFS filesystem.
Service Requirements
The following Windows Services must be running on the server:
Remote Registry
Windows Event Log
Performance Logs & Alerts
Security Requirements
Installation User
A domain user which is a member of the Local Administrators group on the server must be available to run the installation scripts. This is a prerequisite of Microsoft Service Fabric, which is the platform that Cortex Innovation is built upon.
Antivirus Exclusions
It is advised (by Microsoft Service Fabric) that the following antivirus exclusions are created on the server to reduce antivirus processing on Service Fabric artefacts:
Folder Exclusions:
%ProgramFiles%\Microsoft Service Fabric
%ProgramData%\SF
%ProgramData%\SF\Logs
Process Exclusions:
Fabric.exe
FabricHost.exe
FabricInstallerService.exe
FabricSetup.exe
FabricDeployer.exe
ImageBuilder.exe
FabricGateway.exe
FabricDCA.exe
FabricFAS.exe
FabricUOS.exe
FabricRM.exe
FileStoreService.exe
A script is provided during installation to add these exclusions for Windows Defender. If any other antivirus software is running, these will need to be added manually.
If adding the exclusions manually, the Process Exclusions should be done before installation occurs, as the processes will be used during installation of the application and antivirus software can cause the installation to fail or timeout. Folder Exclusions may need to be added after installation has occurred as some antivirus software needs the folders to exist.
Port Requirements
Cortex Innovation and Microsoft Service Fabric require a range of firewall ports to be opened between the server and specific services.
If you are using Windows Firewall, some ports are opened during installation and others are opened dynamically as needed. If any other firewall is used, it will be necessary to add the rules described in Port Requirements to open the correct ports.
The Cortex.Innovation.Test.PortUsage.ps1 script is provided during installation to test the ports on the server and make sure they do not overlap with any other programs; most ports may be altered if this is the case, the description will say if this is not possible.
Additional Web Application Server Requirements
Security Requirements
Installation User
Domain users must be available to run the Application Pools for Gateway and Flow Debugger Service. These users must be given Log on as a service and Log on as a batch job permissions otherwise the Application Pools will not be able to run. Information about how to do this will be given during installation.
For Flow Debugger Service, the NETWORK SERVICE user can also be used.
Domain Requirements
For Gateway, only Windows domains with an Active Directory domain controller running Active Directory Domain Services are supported.
Supported versions of Active Directory are listed below:
Windows Server Standard and Datacenter editions are supported. Filesystem must be NTFS and networking must use IPv4. Linux is not supported, but may be in the future. ↩︎
SQL Server Express, Standard and Enterprise are supported. Other databases are not supported. Note that Transparent Data Encryption is not supported on SQL Server Express. ↩︎
PowerShell 5.1 ships with Windows Server 2016 and 2019. ↩︎
IIS is supported; other web servers, including IIS Express are not supported. ↩︎
Ships as a windows role within Windows Server 2019. ↩︎
Ships as a windows role within Windows Server 2016. ↩︎
3.1.2.2.3 - Install Application Server
Information about installing the Application Server.
Install Application Server
This guide describes how to install the Application Server components on the server. Please ensure that the Prerequisites have been read before starting this installation.
Make Installation Artefacts Available
Copy the following artefacts to a folder on the server (the version numbers may differ):
Cortex Innovation 2022.9 - Block Packages.zip
Cortex Innovation 2022.9 - App Services.zip
Cortex Innovation 2022.9 - App Server Install Scripts.zip
Extract the Cortex Innovation 2022.9 - App Server Install Scripts.zip file to a folder with the same name.
Install Microsoft .NET Framework 4.7.1
Microsoft Service Fabric requires a minimum of Microsoft .NET Framework 4.7.1 to be installed on the server.
To find the version of the framework that is installed:
On the Start menu, choose Run.
In the open box, enter regedit.exe. You must have administrative credentials to run regedit.exe.
In the Registry Editor, open the subkey HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full.
If the Full subkey is not present, then you do not have the .NET Framework 4.5 or later installed.
Check for a DWORD value named Release. The existence of the Release DWORD indicates the .NET Framework 4.5 or newer has been installed on that computer. If the value is 461308 or over then at least .NET Framework 4.7.1 is installed and no further steps need to be taken. If it is not installed, continue with the following steps to install it.
These are non-compulsory security measures, recommended to be applied to the server, in order to prevent potential attacks that exploit known industry security vulnerabilities.
Applying these measures may impact other applications running on your server. Therefore, it is your responsibility to ensure that other applications and their clients will not be affected by the changes.
Only Use Recommended Encryption Algorithms and TLS Protocols
A collection of registry settings need to be applied to guarantee your server is only using the recommended encryption algorithms and TLS protocols. Information about these settings can be found at SSL Best Practices.
Warning
Disabling specific TLS versions or specific Cipher Suites can have impact on Cortex components themselves as well as their communication capabilities with third party systems and services, e.g. Flow Debugger Service executing flows with blocks which communicate with 3rd parties via PowerShell or REST. All parties communicating together must support a shared protocol version and cipher suite, otherwise they will not be able to establish a secure communication link between each other.
The settings can be applied by running a script. Be aware that the server will be restarted when the script is run. Apply the settings by following these instructions:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Install.SSLBestPractices.ps1 script using the following command:
.\Cortex.Innovation.Install.SSLBestPractices.ps1
Note
To avoid answering all of the prompts -Override 0 can be added to the end of the script. This will automatically apply all settings and forcibly restart the server.
If -Override 0 has been specified no further steps need to be taken and you can move on to the next section when the server has restarted.
To use all the recommended settings click Apply all to the first prompt.
To selectively apply each setting select Choose which to apply. Each change will then be prompted with a Yes/No confirmation before applying.
Restart the machine when the script asks.
Add Antivirus Exclusions
If Windows Defender is not running on the server, ensure that the Antivirus Exclusions have been added to the running antivirus software on the server and continue to the next section, otherwise follow these steps:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Add.WindowsDefenderExclusions.ps1 script using the following command, modifying the ApplicationServers value to contain the NETBIOS name or fully qualified domain name of the server:
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on the server and press OK.
A message will indicate that the script has completed successfully.
Check Port Usage
To check all necessary ports are free, follow these steps.
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Run the Cortex.Innovation.Test.PortUsage.ps1 script using the following command, modifying the ApplicationServers value to contain the NETBIOS name or fully qualified domain name of the server:
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on the server and press OK.
If all ports are free, the script will report the following:
All ports required by Cortex Innovation are free
If this is the case, continue to the next section. Otherwise, consult the messages returned by the script, which will give details about how to modify the Cortex.Innovation.Install.Config.json configuration file, in the Cortex Innovation 2022.9 - App Server Install Scripts folder, to use different ports. This will be used later during installation.
The Cortex.Innovation.Test.PortUsage.ps1 script cannot currently re-check modified ports in the configuration file so these need to be manually checked to see that they are free.
Configure Installation Script
In the Cortex Innovation 2022.9 - App Server Install Scripts folder, locate the Cortex.Innovation.Install.ps1 script and open it with a text editor.
Choose the tab below that matches the configuration for this installation, then update the script to match, changing the parameters according to the details given below:
Configure this value with the location of the App Services zip file on the server.
BlockPackagesPath
Configure this value with the location of the Block Packages zip file on the server.
ApiGatewayBasicAuthUserName
Configure this value with the username that will be used for Basic Authentication when making HTTPS requests to the API Gateway Service (e.g. starting production flows).
Currently only Basic Authentication using a single user is supported, OAuth2 will be supported in a future release.
Configure this value with the password that will be used for Basic Authentication when making HTTPS requests to the API Gateway Service (e.g. starting production flows). This should be Cortex Encrypted.
A name identifying the platform being installed. This must have no spaces or symbols. It will be appended to the node names that are displayed in Service Fabric Explorer.
ApplicationServerIPv4Addresses
The IPv4 address of the server.
ServerCertificatePath
The local path of a .PFX certificate file on the server. Environment variables cannot be used.
This is only needed if installing with CA Certificates (Recommended). The certificate should meet the Certificate Requirements.
This certificate will be used for:
Securing communication between the Application Services.
Allowing Application Services to identify themselves to clients such as Gateway.
Preventing unauthorised nodes from joining the single node cluster.
Connecting to Service Fabric Explorer from each of the Application Servers.
Warning
It is critical to set a reminder to update certificates in good time before they expire. If they expire then the platform will cease to function and Cortex Service Portal must be contacted for support.
ServerCertificatePwd
The password for the .PFX certificate file specified in ServerCertificatePath.
This is only needed if installing with CA Certificates (Recommended).
UseSelfSignedCertificates
Installs Application Services and required infrastructure using generated Self-Signed Certificates rather than CA Certificates.
Not recommended for production use.
SkipLoadBalancer
Installs Application Services and required infrastructure without installing a load balancer.
Credential
The credentials of the user which will be used to perform remote operations on the server. It must be a domain user that is a member of the local Administrators group on the server.
This does not need to be changed, a prompt will appear to enter this information when the script is run.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
More advanced configuration (such as changing ports) can be undertaken by modifying the Cortex.Innovation.Install.Config.json file but this shouldn’t be required for most installations. More information about this can be found at Advanced Application Server and Load Balancer Configuration Changes.
Save and close Cortex.Innovation.Install.ps1.
Test Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Type the following command into PowerShell:
.\Cortex.Innovation.Install.ps1-WhatIf
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to test the installation script.
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on the server and press OK.
A password prompt will appear. Enter a password which will be used to create a user in RabbitMQ.
Wait for the command to finish. It will display the output of the installation command without making any changes to the system.
Check that there have been no errors in the script; these would appear in red in the console.
If there are no errors, continue to the next section; otherwise, check if the errors have any instructions for rectifying the issue and follow them.
If there are no useful instructions, check that all previous steps have been followed correctly and, if not, rectify it and run the command again.
If this does not work, please contact Cortex Service Portal for further assistance. The WhatIf script will have created a temporary version of the config file in the script location, showing what changes would be made to it when the script runs. The name is appended with -WhatIf (e.g. Cortex.Innovation.Install.Config-WhatIf.json). This file can be provided when obtaining support.
Run Installation Script
Type the following command into PowerShell:
.\Cortex.Innovation.Install.ps1
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install HA Services and the required infrastructure.
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on the server and press OK.
A password prompt will appear. Enter a password which will be used to create a user in RabbitMQ. This should be entered carefully and recorded as it may be needed if seeking support from Cortex Service Portal. Press OK.
Wait for the script to finish running. This should take approximately 10 minutes.
Check that there have been no errors in the script; these would appear in red in the console.
If there are any errors, then please follow any instructions given within them to rectify the situation, check your configuration files, and retry the installation.
In some circumstances, retrying may error due to components being installed already. In this case please run the following command, followed by the original installation command:
Import the certificate, used in the ServerCertificatePath parameter of the Configure Installation Script section, to your Current User certificate store. This can be achieved by double clicking on the certificate .PFX file and following the wizard.
If using self-signed certificates, the certificate can be retrieved by using the Manage Computer Certificates tool in Windows to export the CortexServerCertificate from the Personal store and then importing it to the Current User store by double-clicking on it and following the wizard.
Open a web browser.
Navigate to https://server.domain.com:9080/Explorer, where server.domain.com is the fully qualified domain name of the server. Replace 9080 with new httpGatewayEndpointPort value if it was changed during configuration.
The screen should resemble that in the following figure:
Healthy Service Fabric Explorer Cluster
The status circles should be entirely green - this indicates that the node and all services and instances are healthy. Other status pages can be accessed by expanding items in the leftmost pane. Issues can be tracked down to the failing component by expanding items with warning triangles or error icons on. The next few diagrams show the status pages for a healthy system.
After expanding the application, clicking on any of the services should display a green circle and Status = Active:
Healthy Service Fabric Explorer Service
After expanding either of the services, clicking on any of the instances/partitions should display a green circle and Status = Ready:
Healthy Service Fabric Explorer Instance
Clicking on any of the nodes at the bottom of the leftmost pane should display a green circle and Status = Up:
Healthy Service Fabric Explorer Node
If any warning triangles appear, wait for 5 minutes or so as the cluster may still be starting up. If the cluster looks OK, go to the next section.
If the warnings persist or anything on the screen goes red, expand the items to find the individual services and instances which have errors or warnings. Warnings should not be ignored as they can indicate that the service can’t start but is still in the retry phase. Error and warning messages should be displayed on the status screens and should indicate what is wrong.
If no useful message can be seen here, the service log files may contain more information. These can be found on the server at:
%ProgramData%/Cortex/Cortex API Gateway Service
%ProgramData%/Cortex/Cortex Flow Execution Service
If no solution can be found, please contact Cortex Service Portal for further assistance.
Preserve installation files
Ensure that the installation files are backed up or kept on the server, especially the scripts and config files that have been modified. This will make it easier to perform further actions in future, such as troubleshooting, certificate rollover, uninstallation, reinstallation and updates.
3.1.2.2.4 - Upgrade v7.2 Gateway to Include Innovation
Information about upgrading v7.2 Gateway with Innovation functionality.
Upgrade v7.2 Gateway to Include Innovation
This guide describes how to upgrade Gateway on v7.2 to include Innovation. Please ensure that Install Application Server has been completed before starting this installation. These steps assume that the v7.2 version of Gateway and its prerequisites have already been installed.
The steps to add Innovation functionality to 7.2 are:
Install Flow Debugger Service
Upgrade Gateway
Make Installation Artefacts Available
Copy the following artefacts to a folder on the machine (the version numbers may differ):
Cortex Innovation 2022.9 - Web App Server Install Scripts.zip
Extract the Cortex Innovation 2022.9 - Web App Server Install Scripts.zip zip file to a folder with the same name.
Install Prerequisites
Licensing
Ensure that a valid Cortex licence file named Cortex.lic exists on the server, in the location %ProgramData%\Cortex\Licences. If it does not, follow the instructions located at Licensing Requirements.
Install Flow Debugger Service
Get Application Pool User
A domain user account is required for the Flow Debugger Service web application pool and must be created prior to performing the installation. In line with best practices, this account should not be used for any purposes other than those specified for the Flow Debugger Service. Alternatively, the NETWORK SERVICE user may also be used.
This user must currently have access to the default NuGet directory, in order to load block packages correctly. To add permissions for the user take the following steps:
Navigate to %SystemRoot%\System32\config\systemprofile\AppData\Roaming\ and create a new folder named NuGet if one does not exist.
Right-click on the NuGet folder and click Properties.
In the dialog, click the Security tab.
Click the Edit... button.
Click the Add... button.
Enter the username of the application pool user and click OK.
In the Permissions section at the bottom, check Full control
Click OK.
The user must be given Log on as a service and Log on as a batch job permissions. To do this take the following steps:
Navigate to Start -> Administrative Tools -> Local Security Policy.
In the Local Security Policy dialog, expand the Local Policies node then select User Rights Assignment.
Take the following steps for the Log on as a service and Log on as a batch job policies:
In the right-hand panel, double-click on the policy.
In the Properties dialog, click on the Add User or Group button.
Note
It is possible to use the Advanced… button to look up names rather than entering them manually. Various filters can be set to find the correct user or group more easily. Multiple users can be selected by holding down CTRL while clicking. OK adds the selected users or groups into the Enter the object names to select text box.
Type the name of the application pool user account into the Enter the object names to select text box. Click the Check Names button to confirm that the user exists.
Click OK on the Select Users dialog, and then confirm the user is correct by clicking OK on the Properties dialog.
Configure Installation Script
In the Cortex Innovation 2022.9 - Web App Server Install Scripts folder, locate the Cortex.Innovation.Install.FlowDebuggerService.ps1 script and open it with a text editor.
Choose the tab below that matches the configuration for this installation, then update the script to match, changing the parameters according to the details given below:
Configure this value with the password that will be used for Basic Authentication when Gateway makes HTTPS requests to the Flow Debugger Service.
This password should be Cortex Encrypted. For security reasons it is recommended that the default value ADA9883B11BD4CDC908B8131B57944A4 should be changed.
Enables Flow Debugger Service to communicate with Gateway using generated Self-Signed Certificates rather than CA Certificates.
Not recommended for production use.
Credential
The credentials of the user that will be used to run the Debugger application pool in IIS.
This does not need to be changed, a prompt will appear to enter this information when the script is run.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
Save and close Cortex.Innovation.Install.FlowDebuggerService.ps1.
Run Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Web App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Web App Server Install Scripts"
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install the Flow Debugger Service.
A credentials prompt will appear. Enter the credentials of the user that should run the Debugger application pool in IIS. If using the NETWORK SERVICE user, enter any user as the username and leave the password blank; the NETWORK SERVICE user will need to be selected in the final step.
Wait for the script to finish running. This should take approximately 2 minutes.
An error may have appeared saying:
The Windows Process Activation Service service is not started.
This can be ignored.
Check that there have been no other errors in the script; these would appear in red in the console.
If there are any errors, then please follow any instructions given within them to rectify the situation, and retry the installation.
If the errors do not give any instructions on how to rectify, please contact Cortex Service Portal for further assistance.
If using NETWORK SERVICE for the application pool user:
Open Internet Information Services (IIS) Manager.
On the left, expand the server node.
Click Application Pools.
Right-click on the Debugger application pool and select Advanced Settings....
In the Advanced Settings dialog, click on Identity and then click the ellipses (...).
In the Application Pool Identity dialog, select Built-in account, then select NetworkService from the drop-down, then click OK.
Right-click on the Debugger application pool and click Recycle....
Upgrade Gateway
Configure Installation Script
In the Cortex Innovation 2022.9 - Web App Server Install Scripts folder, locate the Cortex.Innovation.Install.Gateway.ps1 script and open it with a text editor.
Configure the script according to the details given below:
Configure this value with the location of the Cortex Innovation 2022.9 - Gateway.zip file on the installation server.
GatewayApplicationIISPath
Change to the correct Site Name/Application if either was modified from the defaults (Cortex/gateway) when creating the website or application.
FeatureFlags
Replace InnovationId with the Cortex Innovation feature identifier, which should have been provided by Cortex when fulfilling the Licensing Requirements, if it wasn’t it should be requested using Cortex Service Portal.This will overwrite the FeatureFlags value in the Gateway web.config.
ServiceFabricApiGatewayEndpoint
Replace server.domain.com with the fully qualified domain name of the server. The port should be specified as 8722 and there must be a trailing slash, e.g. https://server.domain.com:8722/.
This will overwrite the ServiceFabricApiGatewayEndpoint value in the Gateway web.config.
ServiceFabricUsingSelfSignedCertificates
Configure the value as $false if you used valid CA certificates when installing the Application Server, $true if you used self-signed certificates.
This will overwrite the ServiceFabricUsingSelfSignedCertificates value in the Gateway web.config.
ServiceFabricApiGatewayBasicAuthUsername
This must be changed if you used a non-default ApiGatewayBasicAuthUserName when installing the Application Server; if so, this value must be configured to the one used.
This will overwrite the ServiceFabricApiGatewayBasicAuthUsername value in the Gateway web.config.
ServiceFabricApiGatewayBasicAuthPassword
This must be changed if you used a non-default ApiGatewayBasicAuthPassword when installing the Application Server; if so, this value must be configured to the one used. It can be Cortex Encrypted.
This will overwrite the ServiceFabricApiGatewayBasicAuthPassword value in the Gateway web.config.
DotNetFlowDebuggerEndpoint
Replace server.domain.com with the fully qualified domain name of the Web Application Server.
This will overwrite the DotNetFlowDebuggerEndpoint value in the Gateway web.config.
DotNetFlowDebuggerBasicAuthUsername
This must be changed if you used a non-default FlowDebuggerBasicAuthUserName when installing the Flow Debugger Service; if so, this value must be configured to the one used.
This will overwrite the DotNetFlowDebuggerBasicAuthUsername value in the Gateway web.config.
This will overwrite the DotNetFlowDebuggerBasicAuthPassword value in the Gateway web.config.
DotNetFlowDebuggerUsingSelfSignedCertificates
Configure the value as $false if you are using valid CA certificates to secure the site containing Gateway and Flow Debugger Service, $true if using self-signed certificates.
This will overwrite the DotNetFlowDebuggerUsingSelfSignedCertificates value in the Gateway web.config.
Test
This does not need to be changed, it will be set at a later stage.
AcceptEULA
This does not need to be changed, the EULA will be accepted at a later stage.
FilePath
The filename that installation logs are written to. If this should be written to a different location than where the installation files are then a full path should be specified.
Save and close Cortex.Innovation.Install.Gateway.ps1.
Test Installation Script
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - Web App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - Web App Server Install Scripts"
Type the following command into PowerShell:
.\Cortex.Innovation.Install.Gateway.ps1-Test
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to test the configuration.
In the event of any errors, there will be an error message displayed at the end of the output with a line confirming the Error Count.
Run Installation Script
Ensure the Gateway application pool is stopped:
Open Internet Information Service (IIS) Manager.
In the left pane, expand the server node.
Click Application Pools to display a list of the Application Pools.
Right-click the Cortex Gateway application pool and select Stop.
Note
Failure to stop the application pool will result in a permissions error when installing Gateway.
Type the following command into PowerShell:
.\Cortex.Innovation.Install.Gateway.ps1
Please read the End User Licence Agreement which can be found here. Once you agree to the terms, add the flag -AcceptEULA to the command entered above, e.g:
Run the PowerShell command to install Gateway.
In the event of any errors, there will be an error message displayed at the end of the output with a line confirming the Error Count.
Start the Gateway application pool:
Open Internet Information Service (IIS) Manager.
In the left pane, expand the server node.
Click Application Pools to display a list of the Application Pools.
Right-click the Cortex Gateway application pool and select Start.
Once the application pool has been started, the site will be available on <protocol>://<host>:<port>/<webapplicationname>, e.g. https://localhost/gateway.
Note
If the application pool does not stay started, ensure that the user it runs as has Log on as a service and Log on as a batch job permissions or belongs to a group that has those permissions.
Information about trying out Cortex Innovation for the first time.
Try it out
This guide describes how to try out a new Innovation installation to make sure it is working. Please ensure that Setup Gateway has been completed before taking these steps.
Test Debugging Flows
Test the platform by creating a new flow and executing it using the following steps:
Click on the Flows charm, then the + button and click Group to open a dialog.
Enter a name for the group, configure the Permission Groups and click OK to create the group.
Click on the group to open it (refresh the page if it does not appear).
Inside the group, click the + button again and click on Flow(Innovation) to open a dialog. If the menu item is not present, it means that the FeatureFlags in the CortexGateway.SetParameters.xml file was not set properly when installing Gateway. See Troubleshooting for more information.
Enter a name for the flow, configure the Permission Groups and click OK to create the flow.
The flow should be displayed with a start flow block and end flow block. A list of block palettes should be displayed down the left hand side:
New Flow - Number of palettes may differ
If the blocks in the flow do not display or the palettes are not visible, see Troubleshooting for more information.
Add a Set Variable block and connect it between the start and end blocks.
Click the Set Variable block to open the Property Editor.
Set the Value property to the expression DateTimeOffset.Now.
Type Result into the Variable property and click Create Result.
In the Variable Editor, set Is Output Variable? to true for the new Result variable.
Set a breakpoint on the end block and start the flow. An execution token should appear, the Result variable should show the current time. If the token does not appear, try refreshing the page.
Continue or stop the execution.
Commit the flow.
Test Publishing Production Flows
Log in to Gateway with a user that has the Admin role.
Click on the Settings charm, then Packages.
Click Add Package Definition. Enter a package name and select the new flow to add to the package. Click Save to save the new package.
Click Publish. A success message should appear. If it doesn’t it means that either one or more of the parameters prefixed with Service Fabric in the CortexGateway.SetParameters.xml file was not set properly when installing Gateway, or the Application Services aren’t healthy. See Troubleshooting for more information.
Test Executing Production Flows
Open an HTTP client, such as Postman. Make a request with the following format:
Property
Value
Action
POST
URL
https://{FQDN of server}:8722/api/default/default/flows/{Flow Name}/executions?packageName={Package Name} e.g. https://server.domain.com:8722/api/default/default/flows/NewFlow/executions?packageName=NewPackage
Content Type
application/json
Body
{}
Authentication
Basic
Username
The value used for ApiGatewayBasicAuthUserName when installing Application Services
Password
The value used for ApiGatewayBasicAuthPwd when installing Application Services (Unencrypted)
Note
If you used self-signed certificates when installing the server you will need to disable SSL certificate validation in your HTTP client.
The request should return a JSON object with the output variables of the flow e.g. { "Output": "2022-03-09T07:35:16+0000" }.
Cortex Innovation has now been verified and is ready to use.
3.1.3 - Add Observability to Innovation
Information about installing an observability platform for Innovation.
3.1.3.1 - Grafana
Information about adding a Grafana platform to Innovation, including details about components, supported architectures, prerequisites, installation and configuration instructions.
For instructions on how to set up Grafana and Grafana Loki in the cloud see Grafana Cloud.
3.1.3.1.1 - Architecture
Information about the recommended architecture for a Grafana platform installation.
An agent which ships the contents of local logs to a Grafana Loki instance. It should be deployed to every machine that has a Microsoft Service Fabric node used by Innovation.
Information about the prerequisites required on each server type for installation.
Prerequisites
The prerequisites required for each server role (as described in Architecture) are laid out in this guide. These must be considered before undertaking the installation.
If additional hardware is not available, it is possible to install to the same Web Application server that hosts Cortex Gateway.
The table below specifies additional resources that are recommended to be added to the existing Web Application server:
Server Role
Additional CPU Cores (> 2GHz)
Additional RAM (GB)
Additional Disk (GB)
Web Application Server (Shared with Cortex Gateway)
4+ Recommended 2 Minimum
12+ Recommended 6 Minimum
10+ Recommended 5 Minimum
Note
The application servers (as described in Architecture) to which Promtail will be added have already been installed as part of the Innovation install process and do not require any hardware modifications for the observability platform installation.
For production systems, it is recommended that X.509 SSL certificates are obtained from a Certificate Authority and used for installation. For non-production systems, self-signed certificates may be used. Details on how to create a self-signed certificate can be found at Create Self-Signed Certificates.
An X.509 SSL certificate (standard, wildcard or self-signed) should be used to secure communication between:
Promtail on the Application Servers and the reverse proxy configured for Grafana Loki on the Web Application Server.
Grafana end users and the Grafana Web Application on the Web Application Server.
The wildcard certificate used for installing Innovation can be used if it is available in the .PEM file format, otherwise a new certificate can be obtained from a Certificate Authority, such as Let’s Encrypt, and must meet the following requirements:
Subject field must be in one of the following formats, depending on the certificate type:
Standard certificates must use the standard format (e.g. CN=host.domain.com).
Wildcard certificates must use the wildcard format, pertaining to the domain of the Web Application Server (e.g. CN=*.domain.com).
Subject alternative names must include any additional host names that should be able to be used to access the Grafana Web Application.
Certificate file must be in a .PFX file format, with a known password.
Certificate file must also be available in a .PEM file format.
Certificate file must contain the full chain of certificates.
Certificate file must include the private key.
The files should be placed in a known location on the Web Application Server. This location will be required when configuring Grafana to use HTTPS.
More information about importing the certificate is given during installation.
TLS Requirements
A set of non-compulsory security measures is recommended to be applied to the Web Application Server to prevent attacks that exploit known industry security vulnerabilities. This includes disabling all versions of SSL and TLS apart from TLS 1.2, and disabling all cipher suites apart from the following:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
See SSL Best Practices for a full list of the recommended security changes to be applied.
Apply Recommended Security Measures
Warning
Disabling specific TLS versions or specific Cipher Suites can have impact on other applications as well as their communication capabilities with third party systems and services. All parties communicating together must support a shared protocol version and cipher suite, otherwise they will not be able to establish a secure communication link between each other.
Apply the settings by following these instructions:
Copy from one of the application servers the Cortex.Innovation.Install.SSLBestPractices.ps1 file extracted during the Make Installation Artefacts Available step into a suitable location on the Web Application Server.
Open a Windows PowerShell (x64) window as administrator.
Change the location to the folder where the Cortex.Innovation.Install.SSLBestPractices.ps1 file was copied to using the following command, modifying the path as necessary:
cd "C:\Install"
Run the Cortex.Innovation.Install.SSLBestPractices.ps1 script using the following command:
.\Cortex.Innovation.Install.SSLBestPractices.ps1
To use all the recommended settings click Apply all to the first prompt.
To selectively apply each setting select Choose which to apply. Each change will then be prompted with a Yes/No confirmation before applying.
Restart the machine when the script asks.
Additional Application Server Requirements
These requirements apply to each of the Application Servers.
Security Requirements
Installation User
A domain user which is a member of the Local Administrators group on all Application Servers must be available to perform the installation.
Windows Server Standard and Datacenter editions are supported. Filesystem must be NTFS and networking must use IPv4. Linux is not supported, but may be in the future. ↩︎
IIS is supported; other web servers, including IIS Express are not supported. ↩︎
Ships as a windows role within Windows Server 2019. ↩︎
Ships as a windows role within Windows Server 2016. ↩︎
Information about installing and configuring Grafana on the Web Application Server.
3.1.3.1.3.1 - Install Grafana
Information about installing Grafana on the Web Application Server.
Install Grafana
This guide describes how to install Grafana on the Web Application Server. Please ensure that the Prerequisites have been completed before starting this installation.
Information about configuring Grafana on the Web Application Server.
Configure Grafana
This guide describes how to configure Grafana on the Web Application Server.
Log-in and Change the Password
It is required that on the first log in into Grafana, a new password for the admin user is set up.
The password should be different from the default one.
On the Web Application Server open a web browser.
Browse to http://localhost:3000/.
On the login page, enter admin for the username and password.
Click Log in.
Set a new password for the admin user when prompted to do so.
Configure HTTPS
By default Grafana allows access over the unsecure HTTP protocol. This needs to be modified to allow access only over the secure HTTPS protocol.
Locate sample.ini file in the grafana\conf subfolder in the location Grafana was installed to; by default C:\Program Files\GrafanaLabs\grafana\conf\sample.ini.
Copy sample.ini and paste it in the same location renaming it to custom.ini.
Run a text editor in administrator mode.
In the text editor open the custom.ini Grafana configuration file.
In the server section uncomment the protocol option and set it to HTTPS, e.g.:
In the server section uncomment the cert_file and cert_key options and set them to the certificate .pem and .key filenames and path saved to during the Certificate Requirements step e.g.:
Information about installing and configuring Grafana Loki on the Web Application Server.
3.1.3.1.4.1 - Install Loki
Information about installing Grafana Loki on the Web Application Server.
Install Loki
This guide describes how to install Grafana Loki on the Web Application Server. Please ensure that the Prerequisites have been completed before starting this installation.
Extract content of the downloaded archive to a suitable location, e.g. C:\Loki.
Download the Grafana Loki Install.zip archive and extract its contents alongside the previously extracted Grafana Loki loki-windows-amd64.exe.
This archive contains the loki-local-config.yaml configuration file, NSSM (the Non-Sucking Service Manager program) and PowerShell scripts to help manage Grafana Loki as a Windows service.
Run Windows PowerShell as Administrator.
Change the location to where all the files were extracted to.
Execute the .\Install-Loki.ps1 command to install the downloaded Grafana Loki loki-windows-amd64.exe as a service.
Execute the .\Start-Loki.ps1 command to start the Grafana Loki service.
Information about configuring Grafana Loki on the Web Application Server.
Configure Loki
This guide describes how to configure Grafana Loki on the Web Application Server.
Note
For security reasons, Grafana Loki should be run behind an encrypted and authenticated reverse proxy as it does not provide these features by itself.
Install Certificate
IIS requires the X.509 SSL certificate, obtained in the prerequisites, to be installed on the Web Application Server.
You can import the certificate by right clicking the certificate file, selecting Install Certificate and following the wizard. When prompted, ensure you import it into the Local Machine store and not Current User.
To verify the certificate is imported:
Click the Windows button (Start)
Type certlm.msc and press Enter to open the Certificate Manager dialog
Expand Personal and select Certificates
You should see your certificate in this store
Setup Reverse Proxy with IIS
All of the steps must be carried out on the Web Application Server.
Install IIS Basic Authentication
Run Server Manager.
Expand the Manage menu and select Add Roles and Features.
In the left-hand menu, select Server Selection.
Select the name of the Web Application Server, click Next.
On the Server Roles page, in the Roles tree, expand Web Server (IIS) –> Web Server –> Security.
Select Basic Authentication, click Next.
Click Next to get to the Confirm installation selections page.
When prompted by the Web Platform Installer, click Install.
On the Prerequisites page click I Accept to agree to the license terms for the module.
Once the install has completed, click Finish.
Click Exit to close the Web Platform Installer.
Set Up Reverse Proxy
To set up a reverse proxy, carry out the following configuration.
Add a New Website
Run IIS Manager.
In the Connection pane, expand the server.
Right-click on Sites and select Add Website… from the menu.
In the Add Website window:
Provide the site name, e.g. Grafana Loki.
Set the Physical path to the location where the site will be stored and ensure that the path exists, e.g. C:\inetpub\wwwroot\Grafana Loki.
For Binding set:
Type: https
IP address: All unassigned
Port: 2100
Host name: The fully qualified domain name of the Web Application Server. This must match one of the Subject Alternative Names in the SSL certificate selected in the next step.
SSL certificate: Select the certificate created as part of the Certificate Requirements instructions.
Click OK to add the website.
Enable Basic Authentication
In the Connection pane, browse to Sites.
Select the newly created website.
Double-click on the Authentication icon.
Disable Anonymous Authentication.
Enable Basic Authentication.
Configure URL Rewrite Rule
In the Connection pane, browse to Sites.
Select the newly created website.
Double-click on the URL Rewrite icon.
In the Actions pane, click Add Rule(s)….
Select Reverse Proxy from the Inbound and Outbound Rules section.
Click OK.
If prompted to Add Reverse Proxy Rules, click OK to enable proxy functionality.
In the Inbound Rules section enter localhost:3100 as the server name.
Ensure that Enable SSL Offloading is checked.
Click OK.
Restart the Website
In the Connection pane, browse to Sites.
Select the newly created website.
In the Manage Website pane, click Restart.
Create Loki User
Run Windows PowerShell as Administrator.
Execute the following command to create a new local user on the Web Application Server:
Information about installing and configuring Promtail on the Application Server(s).
3.1.3.1.5.1 - Install Promtail
Information about installing Promtail on the Application Server(s).
Install Promtail
This guide describes how to install Promtail on the Application Server(s). Please ensure that the Prerequisites have been completed before starting this installation.
Extract content of the downloaded archive to a suitable location, e.g. C:\Promtail.
Download the Promtail Install.zip archive and extract its contents alongside the previously extracted Promtail promtail-windows-amd64.exe.
This archive contains the promtail-local-config.yaml configuration file, NSSM (the Non-Sucking Service Manager program) and PowerShell scripts to help manage Promtail as a Windows service.
Run Windows PowerShell as Administrator
Change the location to where all the files were extracted to.
Execute the .\Install-Promtail.ps1 command to install the downloaded promtail-windows-amd64.exe as a service.
Information about configuring Promtail on the Application Server(s).
Configure Promtail
This guide describes how to configure Promtail on the Application Server(s).
Note
These steps must be performed for every Promtail installation in the cluster.
Install Certificate
If a self-signed certificate was obtained in the prerequisites, the CA certificate used to create this certificate must be imported on each Application Server. Otherwise, Promtail will not be able to establish communication with Grafana Loki.
To import the CA certificate:
Copy the cortexCA.pfx CA certificate created during the root CA certificate generation steps into a suitable location on the Application Server.
Double click on the cortexCA.pfx file to import the certificate into the Windows Certificate Store.
Select Local Machine then click Next.
Click Next.
Enter the Export Password which the certificate was generated with then click Next.
Select Place all certificates in the following store.
Click Browse….
Select Trusted Root Certification Authorities, click OK then click Next.
Click Finish.
Configure Promtail
Set Client URL for Grafana Loki
Open the promtail-local-config.yaml configuration file, which is located in the folder alongside the promtail-windows-amd64.exe file.
Set the Grafana Loki URL in the clients section.
The following template has been provided for convenience:
https://<username>:<password>@<loki host address>:<loki reverse proxy port>/loki/api/v1/push
The password which was set for the user during Create Loki User steps.
loki host address
The host address of the machine where the Grafana Loki reverse proxy was configured during Add a New Website steps . This must match the configured host name.
loki reverse proxy port
The port of the Grafana Loki reverse proxy configured during Add a New Website steps. Usually 2100.
A correct URL should be similar to https://username:password@hostaddress:2100/loki/api/v1/push.
Save the file.
Set the positions.yaml File Path
Open the promtail-local-config.yaml configuration file, which is located in the folder alongside the promtail-windows-amd64.exe file.
Set the filename in the positions section to the location where you want the positions.yaml file to be created on Promtail startup.
Create all the folders of the path specified in the previous step.
Save the file.
Note
If the specified path to the folder for the positions.yaml file doesn’t exists, the file will not get created on Promtail startup.
Set the Path to the Cortex API Gateway Service Log Files
Open the promtail-local-config.yaml configuration file, which is located in the folder alongside the promtail-windows-amd64.exe file.
Set the __path__ in the static_configs > targets > labels section to the path of the Logs folder specified in the appSettings.json file during installation of the Cortex API Gateway Service, e.g. "C:/ProgramData/Cortex/Cortex API Gateway Service/Logs/*.json".
Save the file.
Start Promtail
Run Windows PowerShell as Administrator.
Change the location to the folder where the promtail-windows-amd64.exe file is located.
Execute the .\Start-Promtail.ps1 command to start the Promtail Windows service.
Information about setting up Grafana to communicate with the installed Grafana Loki as well as importing and configuring the default set of dashboards.
Setup Grafana
This guide describes where to get the default Cortex Innovation Dashboards from and how to import them for use in Grafana.
Please ensure that the Installations for Grafana and Loki have been completed before starting this section.
Configure Loki Data Source in Grafana
Log in to your configured Grafana instance with a user that has the admin role.
In Grafana, go to Configuration > Data Sources via the cog icon on the left sidebar.
Click the big Add data source button.
Choose Loki from the list.
Configure the data source as follows:
Option
Description
Value
Name
The name of the data source to use in Grafana
Cortex Loki
URL
The address of your Grafana Loki Server
http://localhost:3100
Timeout
The HTTP request timeout in seconds set to the same value as configured in the Grafana Loki loki-local-config.yaml configuration file located alongside the Grafana Loki loki-windows-amd64.exe file.
600
Click Save and Test.
Data source connected and labels found. message should be displayed above the Save and Test
Download the Cortex Innovation Default Dashboards
Download Grafana.Dashboards.zip archive containing the Cortex Innovation default dashboards.
Extract the content of the downloaded archive to a suitable location.
Create Folder for Dashboards
Log in to your configured Grafana with a user that has the Admin role.
To create a folder, click the + icon in the side menu, and then click Folder.
Enter a folder name, e.g. Cortex.
Click Create.
Import Dashboards
Log in to your configured Grafana with a user that has the Admin role.
To import a dashboard, click the + icon in the side menu, and then click Import.
Click the Upload JSON file button.
Note
This button is broken in the Grafana 8.5.3 version and it may be necessary to use your keyboard’s tab button until the Upload JSON file button is highlighted and press Enter.
Locate the Flow Execution Requests.json file extracted from the downloaded Grafana.Dashboards.zip.
Select the file and click Open.
Select the folder in Grafana you wish the dashboard to be saved in, e.g. Cortex.
Select your configured Loki data source from the dropdown menu.
Click Import.
Repeat steps 2 - 8 for the Platform Health.json file.
Configure Data Sources
It is necessary to update the Custom Filter inside the dashboards to use the correct data source.
To do this, follow these steps for all default Cortex Innovation dashboards imported:
Log in to your configured Grafana with a user that has the Admin role.
To open a dashboard:
Click the Dashboards icon in the side menu, and then click Browse.
Click the folder name that the dashboards were imported to.
Click the Flow Execution Requests dashboard to open it.
Open the Dashboard Settings menu via the cog icon in the top right-hand side of the dashboard.
Click Variables on the left-hand side of the page.
Click Custom Filter at the bottom of the Variables list.
Select your configured Loki data source in the Options > Data source drop-down menu.
Click Update.
Click the back button on the top left corner of the page to go back to the dashboard.
Click the + icon next to the Custom Filter to confirm that a list of available filter options is visible.
Repeat steps 2 - 9 for the Platform Health dashboard.
Information about trying out Grafana Observability Dashboards for the first time.
Try it Out
Check Dashboards are Displaying Data
Note
This test uses the test flow published as part of testing the Innovation installation. See Testing HA installation or Testing non-HA installation. An alternative flow can be used that exists on the system and can be executed.
Open an HTTP client, such as Postman. Make a request with the following format:
Property
Value
Action
POST
URL
For HA installation use: https://{FQDN of Load Balancer Server}/api/default/default/flows/{Flow Name}/executions?packageName={Package Name} e.g. https://load-balancer.domain.com/api/default/default/flows/NewFlow/executions?packageName=NewPackage
For non-HA installation use: https://{FQDN of server}:8722/api/default/default/flows/{Flow Name}/executions?packageName={Package Name} e.g. https://server.domain.com:8722/api/default/default/flows/NewFlow/executions?packageName=NewPackage
If you used self-signed certificates when installing the Application Servers you may need to disable SSL certificate validation in your HTTP client.
Once the request has completed, using a web browser, log in to your configured Grafana.
Click the Dashboards icon in the side menu, and then click Browse.
Click the folder name that the dashboards were imported to.
Click the Flow Execution Requests dashboard to open it.
The request made at step 1 should be visible on the dashboard.
Note
If other requests have been made then there may be more than one request visible on the dashboard.
Click the Dashboards icon in the side menu, and then click Browse.
Click the folder name that the dashboards were imported to.
Click the Platform Health dashboard to open it.
The request made at step 1 should be visible on the dashboard.
Note
If other requests have been made then there may be more than one request visible on the dashboard.
3.1.3.1.8 - Advanced Setup
Supporting information about installing and configuring a Grafana observability platform for Cortex Innovation.
3.1.3.1.8.1 - Create Self-Signed Certificates
Information about creating and installing self-signed certificates.
Create Self-Signed Certificates
Self-signed certificates should be generated using OpenSSL which is bundled in the Cortex Web Application Server Installation Scripts:
Setup OpenSSL in PowerShell
Open a Windows PowerShell (x64) window as administrator.
Make a directory in which to store the certificates by running the following command, changing the path as required:
mkdirC:\Certificates
Navigate PowerShell to inside the certificates folder created above, using the following command, modifying the path as necessary:
cd "C:\Certificates"
Temporarily add OpenSSL to the Path environment variable of your system by running the following command, modifying the path according to the location of openssl.exe in the installation scripts on the machine:
$env:PATH+=";C:\Cortex Innovation 2022.9 - Web App Server Install Scripts\OpenSSL"
Generate the Root CA Certificate
Create the root CA private key by running the following command:
opensslgenrsa-outcortexCA.key4096
Generate the root CA certificate signed with the private key:
Copy the following text into a text editor:
RANDFILE= .rnd
[ ca ]default_ca= CA_default # The default ca section[ CA_default ]# Directory and file locations.# SHA-1 is deprecated, so use SHA-2 instead.default_md= sha256
policy= policy_strict
[ policy_strict ]# The root CA should only sign intermediate certificates that match.# See the POLICY FORMAT section of `man ca`.countryName= match
stateOrProvinceName= match
organizationName= match
organizationalUnitName= optional
commonName= supplied
emailAddress= optional
[ req ]# Options for the `req` tool (`man req`).default_bits=2048distinguished_name= req_distinguished_name
string_mask= utf8only
# SHA-1 is deprecated, so use SHA-2 instead.default_md= sha256
# Extension to add when the -x509 option is used.x509_extensions= v3_ca
[ req_distinguished_name ]countryName= Country Name (2 letter code)countryName_min=2countryName_max=2stateOrProvinceName= State or Province Name (full name)localityName= Locality Name (eg, city)0.organizationName = Organization Name (eg, company)organizationalUnitName= Organizational Unit Name (eg, section)commonName= Common Name (eg, your website's domain name)commonName_max=64emailAddress= Email Address
emailAddress_max=40# Optionally, specify some defaults.countryName_default= GB
stateOrProvinceName_default= Hampshire
localityName_default= Southampton
0.organizationName_default = Cortex Ltd
organizationalUnitName_default= Cortex
emailAddress_default= info@cortex.co.uk
[ v3_ca ]# Extensions for a typical CA (`man x509v3_config`).subjectKeyIdentifier=hashauthorityKeyIdentifier= keyid:always,issuer
basicConstraints= critical, CA:true
keyUsage= critical, digitalSignature, cRLSign, keyCertSign
Save the file as ca.cnf in the directory created for the certificates above.
In the PowerShell window, run the following command:
Enter a memorable string as the Export Password when asked, this will be needed when adding the certificate to certmgr.
Import the Root CA Certificate
Double click on the cortexCA.pfx file in the certificates folder to import the certificate into the Windows Certificate Store.
Select Local Machine then click Next.
Click Next.
Enter the Export Password which the certificate was generated with then click Next.
Select Place all certificates in the following store.
Click Browse….
Select Trusted Root Certification Authorities, click OK then click Next.
Click Finish.
Generate the Certificate
Create a private key for the SSL cert by running the following command:
opensslgenrsa-outcortex.key2048
Generate the SSL certificate request:
Copy the following text into a text editor:
RANDFILE= .rnd
[ ca ]default_ca= CA_default # The default ca section[ CA_default ]# SHA-1 is deprecated, so use SHA-2 instead.default_md= sha256
policy= policy_loose
[ policy_loose ]# Allow the intermediate CA to sign a more diverse range of certificates.# See the POLICY FORMAT section of the `ca` man page.countryName= optional
stateOrProvinceName= optional
localityName= optional
organizationName= optional
organizationalUnitName= optional
commonName= supplied
emailAddress= optional
[ req ]# Options for the `req` tool (`man req`).default_bits=2048distinguished_name= req_distinguished_name
string_mask= utf8only
# SHA-1 is deprecated, so use SHA-2 instead.default_md= sha256
# Extension to add when the -x509 option is used.x509_extensions= v3_req
req_extensions= v3_req
[ req_distinguished_name ]countryName= Country Name (2 letter code)countryName_min=2countryName_max=2stateOrProvinceName= State or Province Name (full name)localityName= Locality Name (eg, city)0.organizationName = Organization Name (eg, company)organizationalUnitName= Organizational Unit Name (eg, section)commonName= Common Name (eg, your website's domain name)commonName_max=64emailAddress= Email Address
emailAddress_max=40# Optionally, specify some defaults.countryName_default= GB
stateOrProvinceName_default= Hampshire
localityName_default= Southampton
0.organizationName_default = Cortex Ltd
organizationalUnitName_default= Cortex
emailAddress_default= info@cortex.co.uk
[ v3_req ]basicConstraints= CA:FALSE
keyUsage= nonRepudiation, digitalSignature, keyEncipherment
subjectAltName= @alt_names
[ alt_names ]# Specify all DNS and/or IP addresses that clients can use to access the secured resource.DNS.1 = MACHINE-NAME
DNS.2 = FULLY QUALIFIED MACHINE NAME
DNS.3 = localhost
IP.1 = IP ADDRESS
IP.2 = 127.0.0.1
Modify the section [alt_names] to include all the required DNS names and IP addresses that clients can use to access the secured resource.
Each DNS name or IP address entry must be suffixed with .N where N is the unique index of the DNS name or IP address entry; see below for examples:
Resource URL
Configuration to add
https://cortex.co.uk/gateway
DNS.1 = cortex.co.uk
https://internal.cortex.co.uk/gateway
DNS.2 = internal.cortex.co.uk
https://10.0.0.0/gateway
IP.1 = 10.0.0.0
https://192.168.1.100/gateway
IP.2 = 192.168.1.100
Save the file as san.cnf in the directory created for the certificates above.
In the PowerShell window, run the following command:
Enter a memorable string as the Export Password when asked, this will be needed when adding the certificate to certmgr.
Import the Certificate
Double click on the cortex.pfx file in the certificates folder to get the certificate imported to the Windows Certificate Store.
Select Local Machine then click Next.
Click Next.
Enter the Export Password which the certificate was generated with then click Next.
Select Place all certificates in the following store.
Click Browse….
Select Personal, click OK then click Next.
Click Finish.
3.1.3.1.8.2 - Port Requirements for the Web Application Server
Information about the ports to be opened when installing the Grafana observability platform.
Port Requirements for the Web Application Server
All the required ports for the Web Application Server that forms part of the Grafana observability platform must be opened on any installed firewall. If any other firewall exists between the Application Servers and the Web Application Server, or Grafana users and the Web Application Server, it will be necessary to configure this selection of rules on it. These ports may be altered if there are any conflicts with other application requirements.
Grafana Observability Platform
Name
Description
Default Port(s)
Protocol
Direction
Grafana
The port used by the Grafana web application
3000
TCP
Inbound
Reverse proxy for Grafana Loki
The port used by IIS serving the role of a reverse proxy for Grafana Loki
2100
TCP
Inbound
3.1.3.1.8.3 - SSL Best Practices
Information about the recommended security settings for the Grafana observability platform servers.
SSL Best Practices
A collection of registry settings can be applied during installation to guarantee your server is only using the recommended encryption algorithms and TLS protocols:
Type
Name
Enabled
Ciphers
AES 128/128
✓
AES 256/256
✓
Triple DES 168
✓
DES 56/56
✕
NULL
✕
RC2 128/128
✕
RC2 40/128
✕
RC2 56/128
✕
RC4 128/128
✕
RC4 40/128
✕
RC4 56/128
✕
RC4 64/128
✕
Hashes
MD5
✕
SHA
✓
SHA256
✓
SHA384
✓
SHA512
✓
KeyExchangeAlgorithms
Diffie-Hellman
✓
ECDH
✓
PKCS
✓
Protocols
Multi-Protocol Unified Hello
✕
PCT 1.0
✕
SSL 2.0
✕
SSL 3.0
✕
TLS 1.0
✕
TLS 1.1
✕
TLS 1.2
✓
Cipher Suites
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
✓
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
✓
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
✕
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA25
✕
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
✕
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
✕
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
✕
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
✕
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
✕
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
✕
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
✕
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
✕
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
✕
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
✕
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
✕
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
✕
TLS_RSA_WITH_AES_256_GCM_SHA384
✕
TLS_RSA_WITH_AES_128_GCM_SHA256
✕
TLS_RSA_WITH_AES_256_CBC_SHA256
✕
TLS_RSA_WITH_AES_128_CBC_SHA256
✕
TLS_RSA_WITH_AES_256_CBC_SHA
✕
TLS_RSA_WITH_AES_128_CBC_SHA
✕
TLS_RSA_WITH_3DES_EDE_CBC_SHA
✕
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
✕
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
✕
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
✕
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
✕
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
✕
TLS_RSA_WITH_RC4_128_SHA
✕
TLS_RSA_WITH_RC4_128_MD5
✕
TLS_RSA_WITH_NULL_SHA256
✕
TLS_RSA_WITH_NULL_SHA
✕
TLS_PSK_WITH_AES_256_GCM_SHA384
✕
TLS_PSK_WITH_AES_128_GCM_SHA256
✕
TLS_PSK_WITH_AES_256_CBC_SHA384
✕
TLS_PSK_WITH_AES_128_CBC_SHA256
✕
TLS_PSK_WITH_NULL_SHA384
✕
TLS_PSK_WITH_NULL_SHA256
✕
Warning
Disabling specific TLS versions or specific Cipher Suites can have impact on other applications as well as their communication capabilities with third party systems and services. All parties communicating together must support a shared protocol version and cipher suite, otherwise they will not be able to establish a secure communication link between each other.
3.2 - Set up in the Cloud
Information about setting up observability in the cloud for a Cortex Innovation platform.
3.2.1 - Add Observability to Innovation
Information about setting up an observability platform for Innovation.
3.2.1.1 - Grafana Cloud
Information about adding Grafana Cloud to Innovation, including details about components, supported architectures, prerequisites, installation and configuration instructions.
For instructions on how to set up Grafana and Grafana Loki on-premise see Grafana on-premise.
3.2.1.1.1 - Architecture
Information about the recommended architecture for a Grafana Cloud installation.
An agent which ships the contents of local logs to a Grafana Loki instance. It should be deployed to every machine that has a Microsoft Service Fabric node used by Innovation.
Required
Application Server
Recommended Architecture
The following architecture requires 1..n Application servers and 1 Grafana Cloud managed service.
Information about the prerequisites required on each server type for installation.
Prerequisites
The prerequisites required for each server role (as described in Architecture) are laid out in this guide. These must be considered before undertaking the installation.
Hardware Requirements
The application servers (as described in Architecture) to which Promtail will be added have already been installed as part of the Innovation install process and do not require any hardware modifications for the observability platform installation.
Note
The application servers must have internet access in order to communicate with the Grafana Cloud managed service.
Windows Server Standard and Datacenter editions are supported. Filesystem must be NTFS and networking must use IPv4. Linux is not supported, but may be in the future. ↩︎
3.2.1.1.3 - Set up Grafana
Information about setting up Grafana in the cloud.
Information about setting up Grafana Loki in the cloud.
Set up Grafana Loki
This guide describes how to set up Grafana Loki in the cloud. Please ensure that the Prerequisites have been completed before starting this installation.
In the Add and manage Grafana Cloud integrations and connections click on the Hosted Logs..
In the Choose your usecase section select Send logs from a standalone host.
Enter an Api key name in the Configure promtail to send logs to your Grafana Cloud section and click the Create API key button.
The key name is used in the Grafana Cloud website to easily identify the key after its creation.
Make a note of the value of the url in the client section of the example configuration. Ignore the instruction to copy and paste the whole content.
Information about installing and configuring Promtail on the Application Server(s).
3.2.1.1.5.1 - Install Promtail
Information about installing Promtail on the Application Server(s).
Install Promtail
This guide describes how to install Promtail on the Application Server(s). Please ensure that the Prerequisites have been completed before starting this installation.
Extract content of the downloaded archive to a suitable location, e.g. C:\Promtail.
Download the Promtail Install.zip archive and extract its contents alongside the previously extracted Promtail promtail-windows-amd64.exe.
This archive contains the promtail-local-config.yaml configuration file, NSSM (the Non-Sucking Service Manager program) and PowerShell scripts to help manage Promtail as a Windows service.
Run Windows PowerShell as Administrator
Change the location to where all the files were extracted to.
Execute the .\Install-Promtail.ps1 command to install the downloaded promtail-windows-amd64.exe as a service.
Information about configuring Promtail on the Application Server(s).
Configure Promtail
This guide describes how to configure Promtail on the Application Server(s).
Note
These steps must be performed for every Promtail installation in the cluster.
Configure Promtail
Set Client URL for Grafana Loki
Open the promtail-local-config.yaml configuration file, which is located in the folder alongside the promtail-windows-amd64.exe file.
Replace the Grafana Loki URL template in the clients section with the url value noted down during Set Up Grafana Loki steps.
A correct URL should be similar to https://239948:eyJrIjoiaWVjNzE4MmVjOThkNTgxMMQ5MzIyZjdlMjAyYWY4NWJjO1I1OTc4NSIsIm4iOiJUZXN0S2V5IiwiaWQiOjY4Nzk0MX0=@logs-prod-008.grafana.net/api/prom/push.
Save the file.
Set the positions.yaml File Path
Open the promtail-local-config.yaml configuration file, which is located in the folder alongside the promtail-windows-amd64.exe file.
Set the filename in the positions section to the location where you want the positions.yaml file to be created on Promtail startup.
Create all the folders of the path specified in the previous step.
Save the file.
Note
If the specified path to the folder for the positions.yaml file doesn’t exists, the file will not get created on Promtail startup.
Set the Path to the Cortex API Gateway Service Log Files
Open the promtail-local-config.yaml configuration file, which is located in the folder alongside the promtail-windows-amd64.exe file.
Set the __path__ in the static_configs > targets > labels section to the path of the Logs folder specified in the appSettings.json file during installation of the Cortex API Gateway Service, e.g. "C:/ProgramData/Cortex/Cortex API Gateway Service/Logs/*.json".
Save the file.
Start Promtail
Run Windows PowerShell as Administrator.
Change the location to the folder where the promtail-windows-amd64.exe file is located.
Execute the .\Start-Promtail.ps1 command to start the Promtail Windows service.
Information about setting up Grafana to communicate with the Cloud Grafana Loki as well as importing and configuring the default set of dashboards.
Import Dashboards
This guide describes where to get the default Cortex Innovation Dashboards from and how to import them for use in Grafana Cloud.
Please ensure that the set up for Grafana and Loki have been completed before starting this section.
Download the Cortex Innovation Default Dashboards
Download Grafana.Dashboards.zip archive containing the Cortex Innovation default dashboards.
Extract the content of the downloaded archive to a suitable location.
Create Folder for Dashboards
Log in to Grafana Cloud with a user that has the Admin role.
Hover over the Dashboards icon in the side menu, and then click + New folder.
Enter a folder name, e.g. Cortex.
Click Create.
Import Dashboards
Log in to Grafana Cloud with a user that has the Admin role.
Hover over the Dashboards icon in the side menu, and then click Import.
Click the Upload JSON file button.
Locate the Flow Execution Requests.json file extracted from the downloaded Grafana.Dashboards.zip.
Select the file and click Open.
Select the folder in Grafana you wish the dashboard to be saved in, e.g. Cortex.
Select your configured Loki data source from the dropdown menu.
Click Import.
Repeat steps 2 - 8 for the Platform Health.json file.
Configure Data Sources
It is necessary to update the Custom Filter inside the dashboards to use the correct data source.
To do this, follow these steps for all default Cortex Innovation dashboards imported:
Log in to Grafana Cloud with a user that has the Admin role.
To open a dashboard:
Hover over the Dashboards icon in the side menu, and then click Browse.
Click the folder name that the dashboards were imported to.
Click the Flow Execution Requests dashboard to open it.
Open the Dashboard Settings menu via the cog icon in the top right side of the dashboard.
Click Variables on the left-hand side of the page.
Click Custom Filter in the Variables list.
Select your configured Loki data source in the Options > Data source drop-down menu.
Click Update.
Click the back button on the top left corner of the page to go back to the dashboard.
Click the + icon next to the Custom Filter to confirm that a list of available filter options is visible. If Grafana Loki has not received any logs from Promtail there will be no options available for selection.
Repeat steps 2 - 9 for the Platform Health dashboard.
Information about trying out Grafana Observability Dashboards for the first time.
Try it Out
Check Dashboards are Displaying Data
Note
This test uses the test flow published as part of testing the Innovation installation. See Testing HA installation or Testing non-HA installation. An alternative flow can be used that exists on the system and can be executed.
Open an HTTP client, such as Postman. Make a request with the following format:
Property
Value
Action
POST
URL
For HA installation use: https://{FQDN of Load Balancer Server}/api/default/default/flows/{Flow Name}/executions?packageName={Package Name} e.g. https://load-balancer.domain.com/api/default/default/flows/NewFlow/executions?packageName=NewPackage
For non-HA installation use: https://{FQDN of server}:8722/api/default/default/flows/{Flow Name}/executions?packageName={Package Name} e.g. https://server.domain.com:8722/api/default/default/flows/NewFlow/executions?packageName=NewPackage
If you used self-signed certificates when installing the Application Servers you may need to disable SSL certificate validation in your HTTP client.
Once the request has completed, using a web browser, log in to your configured Grafana.
Click the Dashboards icon in the side menu, and then click Browse.
Click the folder name that the dashboards were imported to.
Click the Flow Execution Requests dashboard to open it.
The request made at step 1 should be visible on the dashboard.
Note
If other requests have been made then there may be more than one request visible on the dashboard.
Click the Dashboards icon in the side menu, and then click Browse.
Click the folder name that the dashboards were imported to.
Click the Platform Health dashboard to open it.
The request made at step 1 should be visible on the dashboard.
Note
If other requests have been made then there may be more than one request visible on the dashboard.
4 - Guides
This section includes all guides for the Cortex Innovation platform.
4.1 - Cortex API Gateway Service
The Cortex API Gateway Service.
4.2 - Cortex Flow Debugger Service
The Cortex Flow Debugger Service.
4.3 - Cortex Flow Execution Service
The Cortex Flow Execution Service.
4.4 - Cortex Gateway
The centralised web-based portal for accessing all user applications and tooling in the Cortex Innovation platform.
4.4.1 - Cortex Gateway Management
Cortex Gateway and Studio Management tools and settings
4.4.1.1 - LDAP Authorisation
Configure RBAC by assining roles to security groups.
4.4.1.2 - LDAP Connection
Connect to an Active Directory using LDAP.
4.4.1.3 - License Consumption
Review current license consumption of flows in master.
4.4.1.4 - Packages
Create and Manage Cortex Innovation Packages
4.4.1.5 - Studio Authorisation
Assign access rights to flows based on security groups.
4.4.1.6 - Studio Export
Create Cortex Studio Packages by exporting flows.
4.4.1.7 - Studio Hierarchy
Manage the location of flows in the Flow Hierarchy.
4.4.1.8 - Studio Import
Import Cortex Studio Packages.
4.4.1.9 - Version Control
High level view of flows out of sync with master. Allow for mass Commit or Get Master
4.4.2 - Help
System level help
4.4.2.1 - Release Notes
Release notes for all currently available Cortex Versions.
4.5 - Cortex Studio
The web-based, low-code, integrated development environment (IDE) for creating, editing, debugging, testing and managing flows that define the logic and actions required to capture and automate simple user tasks through to complex business or IT processes.
4.5.1 - Cortex Studio - East Panel (TBC)
Eastern panel for Property Editor, Execution Viewer and Exceptions
Summary
Property Editor
Add Variables button
Show/Hide Advanced Properties button
Help button
Execution Viewer
Variables Viewer
Variable Details Viewer
Load Value Button
Exceptions Viewer
Settings Editor
Inputs Property
Remarks
Known Limitations
See Also
Related Concepts
4.5.2 - Cortex Studio - Main Display Area
The Main Display Area for developing and managing a flow
Summary
Main Toolbar
Undo
TODO:
What happens when an undo action is taken
What can be undone
Keyboard Shortcuts?
Redo
TODO:
What happens when an redo action is taken
What can be redone
Keyboard Shortcuts?
Start an execution
TODO:
Should this be called ‘starting an execution’ or ‘debugging an execution’
Start execution via API or Studio
describe the steps of starting from API (API call is made to Gateway, Authentication and Authorisation is performed, Gateway proxied called to debugger service, etc)
describe the steps of starting from Studio (User clicks button, call is made to Gateway, Authentication and Authorisation is performed, Gateway proxied called to debugger service, etc)
Image of button and token after button was pressed
Executions are private and only displayed to the user that requested them (Check this is true, look at the APIs).
link debugging in this page to glossary
link ‘what is an execution.md’ debugging/production to glossary
Providing input variables (API or Studio)
literals and expression
Retrieving Output variables (API or Studio)
Break On Exception
TODO
Edit and Continue an Execution
Workspaces
Blocks
Breakpoints
Executions
Executions are represented by tokens on a workspace.
Set Next Block to Execute
Workspace Toolbar
Remarks
Known Limitations
See Also
Related Concepts
4.5.3 - Cortex Studio - Navigation
How to navigate between and in flows
Summary
Breadcrumb trail
Quick Navigation
Swimlane Management
Remarks
Known Limitations
See Also
Related Concepts
4.5.4 - Cortex Studio - Package Management (TBC)
Package Management
Summary
Remarks
Known Limitations
See Also
Related Concepts
4.5.5 - Cortex Studio - Palettes
Block palette information
4.5.6 - Cortex Studio - South Panel (TBC)
Southern panel for Executions, Messages, and Variables
Summary
Executions Grid
Pausing an Execution
Stepping an Execution
Continuing an Execution
Stopping an Execution
Variables Grid
TODO: Add Screenshot of Grid
Creating Variables
TODO: Screenshots, How to create
Viewing Variables
TODO: Screenshots, Searching/Filtering
Modifying Variables
TODO: Screenshots, How to modify
Changing a Variable’s Scope
TODO: Screenshots, how to modify scope
Find the variable in the [Variable Grid][]
Double-click the Scope to load a dropdown menu
Select the desired workspace
If the variable does not appear in the grid, the most likely reason is the variable is not in scope of the workspace currently in focus. To resolve this, either select the appropriate workspace, or change the Scope filter on the [Variable Grid][] to All.
Deleting Variables
TODO: Screenshots, How to delete
Messages Grid
Remarks
Known Limitations
See Also
Related Concepts
4.5.7 - Debugging
Summary
Property Viewer
Remarks
Known Limitations
See Also
Related Concepts
4.5.8 - Cortex Studio - Expression Editor
A guide on how to use the Expression Editor
Summary
TODO: What is used for, etc.
Snippets
TODO: How to Access, Whats Available, etc
Tools
TODO: Full Screen, Find and Replace, Command Menu, Replace All (Ctrl F2), etc
TODO: Create variable from property, create all undefined variables
Remarks
Known Limitations
See Also
Related Concepts
TODO
5 - Tutorials
This section includes all tutorials for the Cortex Innovation platform.
5.1 - Installation
This section includes tutorials about installing the Cortex Innovation platform.
5.2 - Setup
This section includes tutorials about post-installation setup of the Cortex Innovation platform.
5.3 - Development
This section includes tutorials about developing automation using the Cortex Innovation platform.
5.4 - Administration
This section includes tutorials about administering the Cortex Innovation platform.
6 - Reference
This section includes all reference documentation for the Cortex Innovation platform.
6.1 - Concepts
This section includes all reference documentation for concepts required to use Cortex Innovation.
6.1.1 - Fundamentals
Fundamental concepts when working with Cortex Innovation.
6.1.1.1 - Flows
Information regarding what a flow is, how to call other flows and handling exceptions within a flow.
6.1.1.1.1 - What is a Flow?
Information regarding the anatomy of a flow, starting flows, grouping logic within a flow, and handling exceptions within a flow.
What is a Flow?
Summary
A flow is an object in Cortex Studio that contains the logic and actions (in the form of blocks and workspaces) that is able to be executed on a Cortex Innovation platform.
All the logic of a flow can exist on the Top-Level Workspace, however, this can quickly become difficult to maintain and understand as the numbers of blocks increase. Blocks can be grouped into workspaces in order to reduce the complexity and make the flow easier to maintain.
A Workspace block can opened by double clicking it, showing its workspace canvas and the logic inside; this could include blocks for executing specific functions or other workspaces to help separate the logic of the flow further.
A flow can be called from another flow in the following ways:
Using the Run Flow block to trigger the execution of another flow directly
Using the Execute HTTP Request block to trigger a flow through the API Gateway service (this should only be used to call flows published in a separate Cortex Innovation platform)
Input Variables
Sometimes flows require data to be passed to them through the use of input variables (e.g. a flow used to log errors may require a file path for where the logs are saved).
Input variables can be passed into flows in the following ways:
For the Run Flow block, input variables are configured using the Inputs property; for more information see Run Flow Example
Sometimes flows may return data through the use of output variables (e.g. a flow used to interact with a database may return its results).
Output variables are returned to the calling flow in the following ways:
For the Run Flow block, output variables are saved to the Outputs property; for more information see Run Flow Example
For the Execute HTTP Request block, output variables are returned within the ResponseBody of the HttpResponse property; for more information see example of Calling Another Flow
Remarks
Known Limitations
Flows can only be Called Synchronously
Currently it is only possible to call other flows synchronously; this means the calling flow will wait for the called flow to complete its execution before continuing.
In the future it will be possible to call flows asynchronously; this means the calling flow will continue after the called flow starts its execution without waiting for the called flow to complete.
A flow can contain any number of other workspaces that are not the Top-Level Workspace, these act as a means to grouping logic and actions to reduce the complexity and make the flow easier to maintain.
Example Workspace
Start Workspace block
Identifies where the flow execution will start when the workspace is executed
Automatically created when the workspace is created
The Variables Grid can be opened by double-clicking the icon, the scope will be set to Defined (Selected Workspace)
Cannot be deleted
Workspace
A nested workspace within the flow
Canvas on which blocks are placed and connected to create the workspace logic
Nested Workspaces
All the logic of a flow can exist on the Top-Level Workspace, however, this can quickly become difficult to maintain and understand as the numbers of blocks increase. Blocks can be grouped into workspaces in order to reduce the complexity and make the flow easier to maintain.
A Workspace block can opened by double clicking it, showing its workspace canvas and the logic inside; this could include blocks for executing specific functions or other workspaces to help separate the logic of the flow further.
Handle Workspace Exception block can only be used once per execution of a Workspace
The Handle Workspace Exception block will only handle the first unhandled exception within its workspace. Subsequent unhandled exceptions are passed to the next relevant exception handling block. In future this limitation may be removed.
Information regarding what a block is, block properties and their editors, and handling exceptions thrown by a block.
6.1.1.3.1 - What is a Block?
Information regarding the anatomy of a block, types of blocks and their appearance, connecting blocks, and block properties.
What is a Block?
Summary
A block is used to perform an action, or branch based on a condition within a flow.
Blocks are organised into palettes based on the type of object they operate on or the system they interact with (e.g. Blocks that operate on Lists can be found in the Lists palette). Blocks can be dragged from a palette on to a workspace, and connected to one another to create the logic of the flow.
Anatomy of a Block
There are five types of block, each type has its own image, connection ports and properties:
Flow Control Blocks that start a flow or workspace have the following connection ports:
One output port located on the bottom of the block
An execution moves to the input port of the block connected to the output port.
Flow Control Blocks that end a flow or workspace have the following connection ports:
One input port located on the top of the block
An execution passes through the input port, and ends the flow or workspace depending on the logic of the block.
Action Blocks
Action blocks are used to perform an action within a flow. They can operate on an object or interact with a system.
Exceptions thrown by Action blocks can be handled by connecting a Handle Block Exception block to the red output port.
Block Image
The icon of the Action block shows what object or system it interacts with
The icon in the bottom right of the Action block provides further information into what type of action or interaction it will take
Action blocks are square shaped
Action blocks have a pale blue background
Connection Ports
Action blocks have the following connection ports:
One input port located on the top of the block
One output port located on the bottom of the block
One red exception output port located on the right of the block
An execution passes through the input port, executes the block, and if no exception occurs, moves to the input port of the block connected to the output port; if an exception occurs the execution moves to the exception input port of the exception handling block connected to the exception output port.
Decision Blocks
Decision blocks are used to branch within a flow based on a condition.
Block Image
The icon of the Decision block shows what object or system it interacts with
Decision blocks are diamond shaped
Decision blocks have a pale blue background
Connection Ports
Decision blocks have the following connection ports:
One input port located on the top of the block
One output port located on the right the block
One output port located on the bottom of the block
An execution passes through the input port, executes the block, and based on the result of the execution moves to the input port of the block connected to the correct output port.
Exception Handling Blocks
Exception Handling blocks are used to handle exceptions thrown within a flow.
Exceptions can be handled at different levels within a flow; at the block level, the workspace level, and the flow level. For more information see Handling Exceptions.
One red exception input port located on the left of the block
One red exception output port located on the right of the block if they can be chained
One output port located on the bottom of the block
An execution passes through the exception input port, executes the block, and if the exception can be handled, moves to the input port of the block connected to the output port; if an exception cannot be handled the execution moves to the exception input port of the exception handling block connected to the exception output port, for more information see Chaining Block Exception Handling Blocks.
Workspace blocks are used to group logic and actions within a flow in order to reduce the complexity and make the flow easier to maintain. For more information see Workspaces.
Unhandled exceptions thrown within a workspace can be handled by connecting a Handle Block Exception block to the red output port of the Workspace block.
Workspace Blocks have the following connection ports:
One input port located on the top of the block
One output port located on the bottom of the block
One red exception output port located on the right of the block
An execution passes through the input port and executes the workspace block, and if no unhandled exception occurs, moves to the input port of the block connected to the output port; if an unhandled exception occurs the execution moves to the exception input port of the exception handling block connected to the exception output port.
Block Properties
Blocks are configured using Block Properties. Properties pass data to the block which is then used to perform an action, or branch based on a condition within a flow.
Most blocks share Common Properties such as a description for the block. Some blocks have Advanced Properties that do not normally need to be configured but allow for more advanced scenarios.
Block connections help determine the order blocks will be executed in a flow, an execution moves through the flow sequentially
An execution moves from one connected block to another, depending on the logic of the block. Blocks can be connected to each other through the use of connection ports.
There are four types of connections ports
Input Ports - act as the entry point of a block, output ports from one or more other blocks can be connected to an input port
Output Ports - act as the exit point of a block, output ports can only be connected to an input port of one other block
Exception Input Ports - act as the entry point of an exception handling block, exception output ports from one or more other blocks can be connected to an exception input port
Exception Output Ports - act as the exit point of a block when an exception is thrown, exception output ports can only be connected to an exception input port of one exception handling block
Exceptions within a Block
Exceptions thrown within the execution of a block can be handled by connecting a Handle Block Exception block to the red output port. If there is no Handle Block Exception block that can handle the exception then it will be passed to the workspace level to be handled.
Information regarding what a block property is, the types of properties, the different property editors, and block properties that are common or advanced.
6.1.1.3.2.1 - What is a Block Property?
Information regarding the anatomy of block properties, types of property and their appearance, and configuring properties using the available property editors.
What is a Block Property?
Summary
Blocks are configured using Block Properties. Properties pass data to the block which is then used to perform an action, or branch based on a condition within a flow.
Anatomy of a Block Property
There are three types of block property, each type can be configured using one of its supported editors:
Input properties are used to provide values to a block. These properties are used in the block’s execution (e.g. a block to send emails would have input properties for specifying things like the sender, recipients, summary, body, attachments etc.).
Supported Editors
Input properties can be configured using the following editors:
Discarding unwanted output values from blocks such as the Execute SSH Command block that have multiple Output properties
To discard an output value, the Output property should use the built-in ($)_ variable.
InputOutput Properties
InputOutput properties are used to provide values to a block. These properties are used, updated and saved back to a variable during the block’s execution.
Supported Editors
InputOutput properties can be configured using the following editors:
Data Types without a constructor that contains parameters
Information regarding which editors are supported for a Data Type can be found in the “Remarks” section under “Property Editor Support” in the relevant documentation for that Data Type.
Information regarding the Literal, Variable, and Expression Editors.
6.1.1.3.2.2.1 - Literal Editor
Information regarding using the Literal Editor.
Literal Editor
Summary
TODO
Available Types
TODO:
The literal editor will have one or more available types, these types will be either Complex or Basic Types
The types available to the literal editor are restricted by the block property.
It is possible to switch the type of the literal editor to any available type.
Basic Types
TODO:
Single Editor
TODO: Image of basic literal editor
Complex Types
TODO:
Nested editors within a complex type
List and Dictionary Editors
TODO: Image of complex literal editor
Switching Type
TODO:
What are DataType and CurrentType?
An editor can be switched using the type selector (accessed by clicking on the property name)
TODO: Image of type selector
Remarks
Known Limitations
TODO:
There is no literal support for Collection Types or types that have constructors with no parameters.
See Also
Related Concepts
TODO
Related Blocks
TODO
Related Data Types
TODO
External Documentation
TODO
6.1.1.3.2.2.2 - Variable Editor
Information regarding using the Variable Editor.
Variable Editor
Summary
TODO
Using Variables
TODO:
You can use any available variable.
Available variables are restricted by the scope of the currently selected block
All available variables will be shown when the variable editor is empty; typing in the editor will filter the available variables with those that match (contains text) on either the variable name or scope
TODO: Image of using a variable
TODO: Image of selecting available variables
Scoped Variables
TODO:
Available variables are scoped by the workspace of the block selected
Can see variables of the same name that are on accessible scopes
Link to known limitation. If there are two or more variables with the same name, the variable with the closest scope will be always used even if another is selected
TODO: Image of scoped variables (different names and same names)
Accessing Variable Properties or Indexes
TODO:
Properties and indexes can be accessed from the Variable editor
Translation error shown in messages viewer when using properties or indexes incorrectly for variable that is not dynamic
TODO: Image of accessing variable property and index
Missing Variables
TODO:
If a variable does not exist, then a orange border will be shown around the Variable editor
It is possible to create a new variable from a missing one using the variable editor
TODO: Image of orange border for missing variables
Creating Variables
TODO:
If a variable does not already exist, the variable editor can be used to create a new one at the current scope
If the variable name is invalid (C# identifier naming rules) then there will be no option to create a new variable
TODO: Image of option to create a new variable
Renaming Variables
TODO:
If a variable editor already contains a reference to a variable that exists, typing the name of a non-existent variable will provide the option to rename the previously selected variable (and all references to it within the flow) to the new variable name
If the variable name is invalid (C# identifier naming rules) then there will be no option to rename the variable
Renaming a variable does not include any index or method expressions (e.g. renaming to ($)NewVar.ToString() will rename the selected variable to ($)NewVar)
TODO: Image of option to rename a variable
Remarks
Known Limitations
TODO:
If there are two or more variables with the same name, the variable with the closest scope will be always used even if another is selected
Currently, available variables are not restricted based on the type of the variable and if that is valid for the selected property
See Also
Related Concepts
TODO
Related Blocks
TODO
Related Data Types
TODO
External Documentation
TODO
6.1.1.3.2.2.3 - Expression Editor
Information regarding using the Expression Editor to create literal values, expressions, or use variables.
String literals are surrounded by double quotes. For example:
"Example String"
The example above becomes:
Example String
Double quotes that form part of the string, along with the back-slash character and any unicode character codes or hexadecimal character codes, must be escaped by a back-slash character. For example:
"He said \"Come here\x0021\""
The example above becomes:
He said "Come here!"
For verbatim string literals, double quotes that form part of the string literal must be duplicated to give a single double quote character. For example:
In the case of interpolated verbatim string literals, double curly braces are not interpreted literally; they produce a single curly brace character. For example:
$@"This is a single square brace ""["", and this is a single curly brace ""{{"""
The example above becomes:
This is a single square brace "[", and this is a single curly brace "{"
If it is necessary to create an floating point literal of type Single with a value greater than or equal to Single.MinValue or less than or equal to Single.MaxValue, then the floating point literal must be suffixed by the character f or F. For example:
Currently, creating an object using literal syntax is not supported.
Dictionary literal
Currently, creating a dictionary using literal syntax is not supported; any attempt to make a dictionary using literal syntax will create a Structure instead.
A List is an object that consists of a number of ordered items that can be of any data type.
["Example String",1,true,{},[],null]
Lists may be heterogeneous, where the items may be of different data types, or homogeneous, when the items are all of the same data type.
Variables
Variables are named containers for storing values of any data type; a variable’s value can be read, updated, replaced, or removed using variable syntax; where the variable name is prefixed with ($) (e.g. ($)VariableName).
Interpolation is the process of inserting expressions and variables into a String. An interpolated string is declared by prefixing the string with the $ character.
A verbatim string identifies that characters within the string should be processed literally, and do not need to be escaped. However, the following exceptions apply:
In both Verbatim and Interpolated Verbatim strings the double quote character " is escaped by prefixing it with another double quote character
In Interpolated Verbatim strings the curly brace characters { and } are escaped by prefixing them with the same curly brace character
Expression
Result
Notes
@"c:\programs\file.txt"
"c:\\programs\\file.txt"
@"They said ""Hello!"""
"They said \"Hello!\""
The " character is escaped
$@"{{ Some Text }}"
"{ Some Text }"
Interpolated Verbatim String, The curly brace characters are escaped
For examples of creating Lists using constructor expressions, see Create a List<TItem>.
Constructor expressions
Constructors can be used to create a new instance of a Data Type. A Data Type can have multiple constructors, each with different parameters that are used to create the new instance.
Methods on how to create a new instance of a Data Type can be found in the relevant documentation for that Data Type; information regarding how to create a new Data Type using a constructor can be found in the “Remarks” section under “Create a/an <DataType>” (where <DataType> is replaced by the type’s name).
The following examples show two ways a DateTimeOffset can be created using a constructor:
In the examples below assume the variable ($)Year has been set to 2022.
Expression
Result
Notes
new DateTimeOffset()
0001-01-01T00:00:00+00:00
12AM 1st January 0001 with 0 hour UTC offset, the default for a new DateTimeOffset with no parameters
new DateTimeOffset(($)Year, 7, 1, 14, 0, 0, 0, new TimeSpan(1, 0, 0))
2022-07-01T14:00:00+01:00
2PM 1st July 2022 with 1 hour UTC offset
Note that some Data Types should be created via literal values instead of their constructors, these include:
Methods can be used to execute specific functionality. The methods accessible are defined by the Data Type, and information regarding methods can be found in the relevant documentation for that Data Type.
Methods can have parameters passed into them that are then used to execute the functionality, not all methods have parameters. The same method can be defined multiple times, each with different sets of parameters.
In the examples below assume the variable ($)Int has been set to 1.
Properties can be used to read data from and/or write data to a Data Type. The properties accessible are defined by the Data Type, and information regarding properties can be found in the relevant documentation for that Data Type.
Properties can be read-write, read-only, or write-only (extremely rare) depending on the access specified by the Data Type.
Whilst Structures are Collections, they also allow for their keys to be accessed as properties.
In the examples below assume:
($)TimePeriod has been set to {"Years": 1, "Months": 0, "Days": 0, "Hours": 0, "Minutes": 0, "Seconds": 0, "Milliseconds": 0}
($)Structure has been set to {"FirstKey": 1, "SecondKey": 2}
Read-write property, this can be used in Input, Output, and InputOutput Properties. The result column shows reading the property; writing to the property can be achieved by using any Output Property.
($)Structure.FirstKey
1
Read-write property, this can be used in Input, Output, and InputOutput Properties. The result column shows reading the property; writing to the property can be achieved by using any Output Property.
Enum data types have a defined set of values, where each value has an associated String name and Int32 value. Information regarding values can be found in the relevant documentation for that Data Type.
Values within an Enum can be accessed in the same way as properties or can they can be cast from an Int32 value.
In the examples below assume the variable ($)Int has been set to 6.
Expression
Result
Notes
DayOfWeek.Sunday
DayOfWeek.Sunday
Where the name is "Sunday" and the value is 0
(DayOfWeek)($)Int
DayOfWeek.Saturday
Int32 cast to an Enum. Where the name is "Saturday" and the value is 6
Data Types can be cast to other Data Types through the use of explicit casting, this can sometimes result in the loss of information when converting to a type that does not store the same amount of information. Information regarding which types a Data Type can cast to can be found in the “Summary” section under “Can be cast to” in the relevant documentation for that Data Type.
Data Types can be used as other Data Types through the use of implicit casting, this is an automatic process that requires no expression syntax. Information regarding which types a Data Type can be used as can be found in the “Summary” section under “Can be used as” in the relevant documentation for that Data Type.
In the examples below assume the variable ($)Int has been set to 6.
Expression
Result
Notes
(DayOfWeek)($)Int
DayOfWeek.Saturday
Int32 cast to an Enum. Where the name is "Saturday" and the value is 6
(Int16)($)Int
6
An Int32 can be cast to an Int16 as long as value is from -32,768 through 32,767
(Int32)1.9
1
Casting a Double to an Int32 will cause any decimal places to be lost
($)Int
6.0
When using a block property of type Double an Int32 is implicitly cast to Double without any expression syntax
Currently, creating a dictionary using literal syntax is not supported; any attempt to make a dictionary using literal syntax will create a Structure instead.
Dictionaries can be created using expressions, for more information see Dictionary expressions.
When using variables of the same name the closest scoped is used
It is possible to create multiple variables with the same name in the Variables Grid. When using the same name in different workspaces, the variable with the closest scope will be used.
For example:
Top-Level workspace has the variable ($)Variable
Child-Level workspace also has the variable ($)Variable
When executing a block in Child-Level that uses ($)Variable, the variable that is used is the variable defined in Child-Level.
This may change in future to allow developers to specifically select which of the variables with the same name is used in this scenario.
The Description property is available on all blocks. It defaults to the name of the block and can be used to describe the action or function the block is performing. Any text entered in the Description property is displayed next to the block’s icon on the workspace.
Information regarding properties that do not normally need to be configured but allow for more advanced scenarios.
Advanced Properties
Summary
Some blocks have advanced properties that do not normally need to be configured but allow for more advanced scenarios (e.g. A block to send emails would have advanced properties for specifying things like cc, bcc, attachments etc.). Advanced properties may have explicit default values or will be initialised with values that allow the block to run without configuration.
All advanced properties are hidden by default and can be shown by Toggling Advanced Properties, their values will be used in the block’s execution regardless of whether they are hidden or shown.
Toggling Advanced Properties
All advanced properties can be shown or hidden using the Show/Hide Advanced Properties button found on the top right of the Property Editor. This button is used to toggle whether properties are shown or hidden.
Finding Advanced Properties
A property is defined as advanced within the documentation of a Block or Data Type.
Information regarding which properties are advanced for a Block can be found in the “Properties” section. The table within each property in the relevant documentation will have an “Is Advanced” row stating whether the property is advanced or not.
Information regarding which properties are advanced for a Data Type can be found in the “Remarks” section under “Advanced Properties” in the relevant documentation for that Data Type.
Remarks
Known Limitations
Toggling advanced properties is not persisted between blocks
Currently, when advanced properties are shown when editing a block the advanced toggle state is not persisted when switching between blocks.
In future this limitation may be removed.
Toggling advanced properties shows or hides all advanced properties
Currently, it is not possible to show or hide individual advanced properties.
When any variables have their Is Output Variable? property set to true, they will be returned to the caller as items in a Structure when the flow ends.
In the following example ($)TotalUnreadEmails and ($)FoldersWithUnreadEmails are both set as outputs and the following Structure is returned:
Variables must be initialised with data before they can be used in a block.
If an Input or InputOutput property uses a variable that has not been initialised, a Message will be returned stating Variable is not initialised, and the name of the variable will be included within the details of the message. The Message will be:
If a variable has its Is Input Variable? property set to true, and no Default Value has been set, then a value must be provided for the variable when the flow is triggered. When the execution starts, the variable is initialised with the value provided.
Default Value
If a variable has its Set Default Value? property set to true, it will be initialised with the Default Value provided when the flow is executed.
If a variable has its Is Input Variable? and Set Default Value? properties set to true, then it will be initialised with the value provided when the flow is triggered. If no value is provided then it will be initialised with the Default Value.
Block Output Property
Output Properties are used to save values to a variable during the execution of a block, regardless of whether the variable is already initialised or not. The act of saving to an uninitialised variable will initialise it.
When a variable contains a basic data type (e.g. String, Integer, etc), the value will be displayed directly in the Variables Viewer. Strings will be surrounded by double quotes (e.g. "MyString").
Viewing Complex Data Types
When a variable contains a complex data type that is not a collection data type (e.g. Command or FlowException), the value will be displayed as Instance of Command or Instance of FlowException respectively in the Variables Viewer.
When a variable contains a collection data type (e.g. Dictionary, List, or Structure), the Variables Viewer will specify the data type and how many items the collection contains (e.g. Dictionary<string, object> with 2 item(s)).
InputOutput and Output properties are used to save values and update variables during the execution of a block.
Deleting Variables
When an execution exits a workspace, any variables defined within that workspace’s scope will be deleted from the execution. This means the variables:
Are no longer accessible to the execution
Are no longer presented in the Variables Viewer when the flow is being debugged
If the execution re-enters the workspace’s scope, any variables will be re-initialised.
Variable Typing
Variables do not have their own data type; they are named containers for storing data of any data type.
When a variable is used in a Block Property it is checked to ensure the data type it contains is supported by the property. For all data types apart from dynamic any variables containing unsupported data types will be displayed in the Messages Grid, preventing the execution from starting; for variables containing dynamic data types checking will be performed during the block execution, throwing an exception if the data type is unsupported.
Sometimes an unsupported data type can automatically be converted to a supported type through the use of implicit casting; if this is possible the block property will handle this without any input required by the developer. However, if this is not possible an unsupported data type must be converted to a supported type by the developer; this can be done by:
Variables that contain a Collection or String data type can have their respective items or characters accessed using index notation:
[0] gets the first item
[1] gets the second item
["key"] gets the item with the key "key".
Ranges can also be used within index notation:
[0..3] gets three items from the first item (inclusively) (i.e. the first, second, and third item)
[^1] gets the last item
[^2] gets the second to last item
[..] gets all items
[..3] gets three items from the first item (inclusively) (i.e. the first, second, and third item)
[3..] gets all items from the fourth item (inclusively) (i.e. the fourth to the last item)
In the examples below assume:
($)List has been set to [1, 2, 3, 4, 5]
($)Dictionary of type Dictionary<string, Int32> has been set to {"FirstKey": 1, "SecondKey": 2}
($)Structure has been set to {"FirstKey": 1, "SecondKey": [1, 2, 3]}
($)String has been set to "Some Text".
Text
Result
Notes
List[2]
3
The third item in the list is returned
List[0..2]
[1, 2]
The first and second item in the list are returned
List[^2]
4
The second to last item in the list is returned
List[^2..^0]
[4, 5]
The second to last and the last item in the list are returned
List[1..^1]
[2, 3, 4]
The second item to the second to last item in the list are returned
List[..]
[1, 2, 3, 4, 5]
All items in the list are returned
List[..2]
[1, 2]
The first item and the second item in the list are returned
List[2..]
[3, 4, 5]
The third item to the last item in the list are returned
Dictionary["FirstKey"]
1
The item with the key "FirstKey" is returned
Structure["SecondKey"]
[1, 2, 3]
The item with the key "SecondKey" is returned
Structure["SecondKey"][0]
1
The first item within the item with key "SecondKey" is returned
String[0]
'S'
The first character in the string is returned
Using Properties of Data Types
Properties can be used to read data from and/or write data to a variable. The properties accessible are defined by the Data Type, and information regarding properties can be found in the relevant documentation for that Data Type.
Properties can be read-write, read-only, or write-only (extremely rare) depending on the access specified by the Data Type.
Read-write property, this can be used in Input, Output, and InputOutput Properties. The result column shows reading the property; writing to the property can be achieved by using any Output Property.
Structure.FirstKey
1
Read-write property, this can be used in Input, Output, and InputOutput Properties. The result column shows reading the property; writing to the property can be achieved by using any Output Property.
Using Methods of Data Types
Methods can be used to execute specific functionality. The methods accessible are defined by the Data Type, and information regarding methods can be found in the relevant documentation for that Data Type.
Methods can have parameters passed into them that are then used to execute the functionality, not all methods have parameters. The same method can be defined multiple times, each with different sets of parameters.
In the examples below assume the variable ($)Int has been set to 1.
Text
Result
Notes
Int.ToString()
"1"
Method without parameters
Int.ToString("P0")
"100%"
The ToString() method can take parameters in order to format the result. In this case 1 was converted into a percent with zero decimal places
Expression Editor
Variables are named containers for storing values of any data type; a variable can be included within expressions created using the Expression Editor. A variable is used by prefixing the variable’s name with ($) (e.g. ($)VariableName).
Remarks
Case Sensitivity
When using variables in the Variable or Expression Editor, the names are case insensitive. For example, List is the same as list.
Message property cannot be accessed using FlowException.message
Int.ToString()
ToString() method cannot be accessed using Int.toString()
Dictionary["Item1"]
"Item1" item cannot be accessed using the key Dictionary["item1"]
Known Limitations
When using variables of the same name the closest scoped is used
It is possible to create multiple variables with the same name in the Variables Grid. When using the same name in different workspaces, the variable with the closest scope will be used.
For example:
Top-Level workspace has the variable ($)Variable
Child-Level workspace also has the variable ($)Variable
When executing a block in Child-Level that uses ($)Variable, the variable that is used is the variable defined in Child-Level.
This may change in future to allow developers to specifically select which of the variables with the same name is used in this scenario.
When the flow execution exits a workspace, any local-scope variables that have been declared in that workspace are deleted and their values, if any, are lost.
Accessing Variables from Other Scopes
For example, the table below shows a hierarchy of workspaces and which variables are available to each workspace due to their scope:
When using variables of the same name the closest scoped is used
It is possible to create multiple variables with the same name in the Variables Grid. When using the same name in different workspaces, the variable with the closest scope will be used.
For example:
Top-Level workspace has the variable ($)Variable
Child-Level workspace also has the variable ($)Variable
When executing a block in Child-Level that uses ($)Variable, the variable that is used is the variable defined in Child-Level.
This may change in future to allow developers to specifically select which of the variables with the same name is used in this scenario.
Information regarding what a data type is, and the difference between basic and complex data types.
6.1.1.5.1 - What is a Data Type?
Information regarding what a data type is, basic and complex data types and their differences.
What is a Data Type?
Summary
TODO:
Overview of a data type
Difference between Value (value types cannot be null, and have a default value that is not null e.g. int is 0) and Reference Data Types (reference types can be null and have a null default value)
Difference between Basic and Complex Data Types
Value Types
TODO:
Explain what a value type is, and how it can be used
Check Set Variable block and how Value Types work within the block
Setting a new variable to an already existing value type will cause them to be separate instances of the value
The Copy Object block can be used to make a copy of a value type (value types always have a different reference)
Reference Types
TODO:
Explain what a reference type is, and how it can be used
This is referenced by the Set Variable block
Set Variable block is used to set ($)List[0]
When adding ($)Reference to ($)List, the actual reference is added (not a copy)
Setting value of ($)List1 to ($)List2 will cause them to have the same reference. Changes to ($)List1 are reflected in ($)List2
The Copy Object block can be used to make a copy of a type with a different reference
Basic Data Types
TODO:
Explain what a basic data type is
Table of Basic Data Types
Columns - Data Type Name, Value/Reference Type
Strings are a basic data type but are also a reference type.
Complex Data Types
TODO:
Explain what a complex data type is and what makes a data type complex
Includes Complex and Collections (Lists, Dictionaries, structures, etc)
Information regarding null and nullable data types.
Null and Nullable Types
Summary
TODO
Null
TODO
Nullable Types
TODO
Remarks
Known Limitations
TODO
See Also
Related Concepts
TODO
Related Data Types
TODO
Related Blocks
TODO
External Documentation
TODO
6.1.1.6 - Executions
Information regarding what an execution is, starting executions, execution variables, exceptions thrown during an execution, and execution metadata.
6.1.1.6.1 - What is an Execution?
Information regarding the anatomy of an execution.
What is an Execution?
Summary
An execution represents a running instance of a flow, the execution moves through the flow sequentially executing each block saving any outputs to variables. A flow can have one or more executions running at any time, each with their own variables.
The description of the block the execution is currently on
Set Variable
Workspace Name
The name of the workspace the execution is currently in
Setup and Run Child-Flow
Flow Name
The name of the flow the execution is currently running
Parent-Flow
When a flow starts the execution of a child flow using the Run Flow block, any child executions will be shown within a tree in the Executions Grid, for example:
Execution Status
Status
Description
Running
The execution is currently executing
Pausing
The execution is in the process of pausing - e.g. a long running block may have to finish before the execution is paused
Paused
The execution is paused on top of a block - before the block starts to execute
The execution is paused at a breakpoint on top of a block - before the block starts to execute
The execution is paused on the output port of a block - after the block has executed but before the execution has selected which block is next
Exception
The execution is paused on the exception output port - after the block has thrown an exception when break on exception is turned on
Stopping
The execution is in the process of stopping - e.g. a long running block may have to finish before the execution is stopped
Stopped
The execution has ended after having been manually stopped
Ended
The execution has ended normally
Error
The execution has ended after having thrown an exception that was not handled
Show execution on workspace - when this is true, the token will be shown at every step throughout the flow, otherwise the token will only be shown when the execution pauses, hits a breakpoint, or an exception occurs when Break on exception is true
Break on exception - when this is true the execution will pause when an exception occurs
Providing Input Variables
Any flow that has Input Variables defined requires them to be provided when debugging, these may be provided to a flow in the following ways:
From an HTTP request using the inputVariables in the body of the request
Retrieving Output Variables
Any flow that has Output Variables defined can have those variables retrieved after the execution has completed by using the outputVariables in the body of the HTTP response.
Validating a Flow
The flow is validated before it’s debugged, if this is successful an execution will begin.
If there are any issues with the flow then the execution will not start and details of what needs to be resolved will be returned. If the flow was debugged by clicking the Start an execution button, then entries will be displayed in the Messages Grid; if it was debugged by making an HTTP request to Cortex Studio, then a 400 Bad Request is returned.
Set Next Block to Execute allows a developer to choose which block will be executed next for the selected execution, even if this block is not connected to the flow.
Examples of what this can be used to do whilst debugging include:
Retrying a block due to a transient exception such as network connectivity
Retrying a block after using Edit and Continue to fix an incorrectly configured block
Skipping over functionality that is not yet working
Skipping to specific functionality within the flow in order to test it
Running logic that is not part of the flow (e.g. running a clean up script to reset any external data sources for the next execution of the flow)
To see the data in a variable, select the variable in the Variables Viewer and the data will be presented in the Variable Details Viewer. If the data is large enough to negatively affect the performance of Cortex Studio it will not be displayed unless the Load Value Button is clicked.
Any flow that has Input Variables defined can have those variables provided by using the inputVariables in the body of the HTTP request.
Retrieving Output Variables
Any flow that has Output Variables defined can have those variables retrieved after the execution has completed by using the outputVariables in the body of the HTTP response
Validating a Flow
The flow is validated before it’s started, if this is successful an execution will begin.
If there are any issues with the flow then the execution will not start and details of what needs to be resolved will be returned. If the flow was started by making an HTTP request to the Cortex API Gateway Service, then a 400 Bad Request is returned.
If an exception occurs within the workspace of the Handle Flow Exception block and is not handled, the execution will end and then a 500 Internal Server Error is returned.
Logs Generated
There are two ways that logs are generated while executing a flow in Production, they are:
Information regarding what an exceptions is, handling exceptions, and throwing exceptions.
6.1.1.7.1 - What is an Exception?
Information regarding the anatomy of an exception, and properties accessible on an exception.
What is an Exception?
Summary
An exception is thrown during an execution when an issue is encountered whilst executing a flow. Exceptions can occur for a number of reasons, such as:
Exceptions thrown by a block, these can be found in the relevant documentation for that block (e.g. A duplicate key is added to a Dictionary using the Add Item With Key block)
Developer thrown exceptions (e.g. A developer enriches an exception that has already been thrown to provide a more detailed message)
Issues with third-party systems (e.g. A third-party system experiences an error)
Issues with network connectivity (e.g. A target machine is inaccessible)
Issues with permissions (e.g. The execution does not have permission to read a file)
Issues with the environment (e.g. The software installed on a target machine is incorrect)
An exception contains details of what caused the issue, for more information see Anatomy of an Exception.
An exception can be handled in different ways depending on where the exception occurred. For more information see Handling Exceptions.
Anatomy of an Exception
Data within an exception can be accessed using properties.
The following properties are found on all exceptions:
Property
Notes
Example
Exception Type
The type of the exception
PropertyNullException
Message
The exception message, providing information about the exception that occurred. This typically includes the cause of the exception, possible resolutions, and any related information. What is included in an exception’s message can be found in the relevant documentation for that exception
'List' is null; it must be provided with a non-null value.\r\nPlease click the HelpLink for more information on how to fix this.
HelpLink
Help link to aid with troubleshooting and resolution for the exception. There are three types of help links:
Cortex - Help links direct to material within the Cortex Product Portal. This documentation is written and maintained by Cortex and contains information directly related to the Cortex product.
External - Help links direct to externally hosted material about the exception. This documentation is not written or maintained by Cortex.
Custom - Help links are generated by flow developers during the design and development of flows. These help links are configured in the Throw New Exception block, and can link to any resource applicable to the exception.
The error code for the exception, which is used to indicate the reason that the exception occurred, if there are multiple reasons that the exception can occur.
InfiniteLoopException has three error codes, InfiniteLoopErrorCode.IncrementIsZero (100), InfiniteLoopErrorCode.IncrementIsNegative (101), and InfiniteLoopErrorCode.IncrementIsPositive (102)
Inner Exception
Contains the exception that caused this exception, if any. This property is always accessible but will only be visible in the Exceptions Viewer when it contains data.
{"ExceptionType": "PropertyNullException", "Message": "'List' is null; it must be provided with a non-null value.\r\nPlease click the HelpLink for more information on how to fix this.", "HelpLink": "https://v2022.docs.cortex-ia.com/docs/reference/exceptions/common/property/property-null-exception/"}
For more information regarding what properties are accessible on an exception, see the relevant documentation for that exception.
Remarks
Known Limitations
Carriage Return and Line Feed Characters
Carriage Return and Line Feed characters within an exception are supported but will be displayed or written as \r, \n, or \r\n.
In future this limitation may be removed.
Copying Exception Text
The Exceptions Viewer currently does not support traditional copy functionality. A workaround is to highlight the text, then click and drag into another text editor.
Exceptions thrown within the execution of a block can be handled by connecting a Handle Block Exception block to the red exception output port. These blocks allow for specific match criteria to be provided; if an exception matches the criteria it will be handled by the block and can be saved to a variable, otherwise, it will be passed to the next chained exception handling block. This process repeats until the exception is either handled or there are no more blocks in the chain; if the exception is not handled at this level it is passed up to the workspace level.
Matching Exceptions
Handle Block Exception blocks can be configured to handle exceptions that match specific criteria (e.g. The Exception Type or Message contains matching text). If an exception matches the criteria, the exception is handled, saved to a variable if provided, and the execution moves to the block connected to the output port; if the exception does not match the criteria the execution moves to the next chained exception handling block.
Chaining Block Exception Handling Blocks
Handle Block Exception blocks can be chained together by connecting the red exception output port of one block to the red exception input port of another. When an exception is not handled, it will be passed to the next chained exception handling block. This process repeats until the exception is either handled or there are no more blocks in the chain; if the exception is not handled at this level it is passed up to the workspace level.
The Handle Block Exception block can be used to handle all exceptions. This block does not have an exception output port and therefore ends the chain.
Saving the Block Exception
Handle Block Exception blocks can be used to save the handled exception to a variable. If it is not necessary to save the exception to a variable, it may be discarded by setting the block’s Exception property to use the built-in discard variable ($)_.
Handling Exceptions at the Workspace level
Exceptions not handled at the block level are passed up to the workspace level.
The Handle Workspace Exception block can be used to save the handled exception to a variable. If it is not necessary to save the exception to a variable, it may be discarded by setting the block’s Exception property to use the built-in discard variable ($)_.
The logic contained within the Handle Flow Exception workspace must end the execution using an End Flow block. By default, this workspace contains a Start Workspace block connected to an End Flow block, which will cause the flow to end without error.
Handling Exceptions in the Handle Flow Exception block
The Handle Flow Exception block can be used to save the handled exception to a variable. If it is not necessary to save the exception to a variable, it may be discarded by setting the block’s Exception property to use the built-in discard variable ($)_.
Remarks
Known Limitations
The Top-Level Workspace cannot contain a Handle Workspace Exception block
Enforced restrictions to prevent infinite recursion
For each execution of a workspace, the Handle Workspace Exception block will only handle the first unhandled exception within its workspace, this is to prevent infinite recursion within the flow.
Related messages are grouped by the component affected (e.g. A block, or the Settings Editor)
Each message row contains the following:
Property
Notes
Location
Path to the specific part of the component that has caused the issue
Summary
Short description of the issue
Details
Further information about the issue. This may also contain help for resolving the issue
Navigating to the Location of an issue from a message
Double clicking on a message within the Messages Grid will navigate the browser to the affected location.
Remarks
Known Limitations
It is not possible to navigate to a nested literal property from a message
It is not possible to navigate to a nested literal property from a message, clicking the message will cause the browser to navigate to the last property of the top-level literal editor that contains the issue.
In future this limitation may be removed.
It is not possible to navigate to the Settings Editor from a message
It is not possible to navigate to the Settings Editor from a message, clicking the message will do nothing.
Complex Keys do not show sho correctly in the Variable Details Viewer
Currently, if a Dictionary is shown in the Variable Details Viewer and contains Complex Data types as its keys, the data within the variable will not be displayed correctly.
In the future this limitation may be removed.
See Also
Related Concepts
TODO
Related Data Types
TODO
Related Blocks
TODO
External Documentation
TODO
6.1.2.1.2 - Items
Information related to working with Items.
Items
Summary
TODO:
Overview/summary
What is an Item?
How are they accessed?
Link to Indexes
Link to Keys
If you are using C# syntax, then the equality is done using reference equality for reference types, and value equality for value types
If you are using List of Dictionary blocks, then the equality is done using reference equality for reference types and falls back to value equality if no reference was found, and value equality for value types
If you are using C# syntax, then the equality is done using reference equality for reference types, and value equality for value types
If you are using Dictionary blocks, then the equality is done using reference equality for reference types and falls back to value equality if no reference was found, and value equality for value types
Complex Keys do not show sho correctly in the Variable Details Viewer
Currently, if a Dictionary is shown in the Variable Details Viewer and contains Complex Data types as its keys, the data within the variable will not be displayed correctly.
In the future this limitation may be removed.
See Also
Related Concepts
TODO
Related Data Types
TODO
Related Blocks
TODO
External Documentation
TODO
6.1.2.1.5 - Occurrences
Information related to working with Occurrences.
Occurrences
Summary
TODO
Summary
What is an Occurrence?
How are they accessed?
Positive or Negative int properties on blocks that operate on single items
Difference between occurrence and indexes
Positive Occurrences
TODO:
Get First, Second, Third, Nth
Negative Occurrences
TODO:
Get Last, Second from Last, Third from Last, Nth from Last
Remarks
Occurrence Not Present
TODO:
Blocks will either throw an exception if the occurrence is not present (e.g. OccurrenceNotPresentException), or they will handle the occurrence not being present either by performing no operation or by returning a predetermined value.
For example:
Get Index Of Item With Value (returns predetermined value)
Remove Item With Value (no operation performed)
Get Item With Key (throws OccurrenceNotPresentException)
Known Limitations
None
See Also
Related Concepts
TODO
Related Data Types
TODO
Related Blocks
TODO
External Documentation
TODO
6.1.2.2 - Culture
Information related to working with Culture.
6.1.2.2.1 - What is a Culture?
Information regarding what a culture is.
What is a Culture?
Summary
TODO
Types of Culture
TODO:
Link to Culture Pages (Invariant/Current/Specific/Custom)
TODO: Also need sections in working with text (casing, comparisons/equality, O/S settings), dates and time (formats, O/S settings), numbers (formats, O/S settings) etc specifically for how culture affects things - we can then cross link from here
Related Data Types
TODO
Related Blocks
TODO
External Documentation
TODO
6.1.2.2.2 - Invariant Culture
Information related to working with Invariant Culture.
Invariant Culture
Summary
TODO: summary
Remarks
Known Limitations
TODO
See Also
Related Concepts
TODO
Related Data Types
TODO
Related Blocks
TODO
External Documentation
TODO
6.1.2.2.3 - Current Culture
Information related to working with Current Culture.
Current Culture
Summary
TODO: summary
Remarks
Known Limitations
TODO
See Also
Related Concepts
TODO
Related Data Types
TODO
Related Blocks
TODO
External Documentation
TODO
6.1.2.2.4 - Specific Cultures
Information related to working with specific cultures.
Both can be used to define how DateTimeOffset and DateTime values are converted to and from their text representation.
TODO:
*How do they relate to format providers
Standard Format Templates
A standard format template uses a single character format specifier to define the text representation of DateTimeOffset and DateTime values and can be used to define how DateTimeOffset and DateTime values are converted to and from their text representation.
The following table shows all of the standard format templates.
All examples are for a system configured with British culture (i.e. en-GB), and use a local time of 2PM 1st of July 2022 with 1 hour UTC offset, honouring British Summer Time (BST).
In some cases, the standard format string serves as a convenient abbreviation for a longer custom format string that is invariant. Four standard format strings fall into this category: “O” (or “o”), “R” (or “r”), “s”, and “u”. These strings correspond to custom format strings defined by the invariant culture. They produce string representations of date and time values that are intended to be identical across cultures. The following table provides information on these four standard date and time format strings.
TABLE 2
Standard format string Defined by DateTimeFormatInfo.InvariantInfo property Custom format string
“O” or “o” None yyyy’-‘MM’-‘dd’T’HH’:‘mm’:‘ss’.‘fffffffK
“R” or “r” RFC1123Pattern ddd, dd MMM yyyy HH’:‘mm’:‘ss ‘GMT’
TODO: notes about value equality and a worked through example
Reference Type Equality
TODO: notes about reference equality and a worked through example
How Cortex compares objects for equality
TODO: notes about how cortex compares and a worked through example
Notes:List and Dictionary equality is slightly different to normal equality as it will compare first based on reference and then fall back to value - compared to == .Equals .ReferenceEquals - blocks affected
The table below lists some of the most common types of text casing:
Name
Example
Notes
lowercase
"this is lowercase"
All letters in all words are lower cased.
UPPERCASE
"THIS IS UPPERCASE"
All letters in all words are capitalized.
Title Case
"This Is Title Case"
First letter in all words is capitalized, all other letters are lower cased; except for words that are entirely upper cased, such as acronyms, which remain upper cased; spaces and punctuation are preserved.
camelCase
"thisIsCamelCase"
First letter in all words (except the first) is capitalized, all other letters are lower cased, and all spaces and punctuation are removed.
PascalCase
"ThisIsCamelCase"
First letter in all words is capitalized, all other letters are lower cased, and all spaces and punctuation are removed.
Culture Info
Culture Info specifies the culture-specific casing rules used to determine how the case of text is changed.
The table below lists the most common supported culture info:
Name
Text Value
Description
Invariant Culture
CultureInfo.InvariantCulture
Used to compare text using culture-sensitive sort rules and the Invariant Culture. Case of the texts is considered when comparing.
Current Culture
CultureInfo.CurrentCulture
Used to compare text using culture-sensitive sort rules and the Current Culture. Case of the texts is considered when comparing.
In addition to Invariant and Current Culture, there are two other types of culture that can be used:
If a security decision depends on a string comparison or a case-change operation, the application should use the InvariantCulture to ensure that the behavior is consistent regardless of the culture settings of the system. However, the invariant culture must be used only by processes that require culture-independent results, such as system services. Otherwise, it produces results that might be linguistically incorrect or culturally inappropriate.
Current Culture
For Current Culture, the casing rules used to determine how the case of text is changed are culture-sensitive and based on the culture of the operating system the flow execution is running on.
TODO:
Link to Working with Culture -> Current Culture
When to use? If not sure what to choose?
Best practices - all OSes in cluster should be installed with same OS culture and settings etc. - should also be time sync’d
Notes about current culture and a worked through example
Specific Cultures
TODO:
Talk about how there are a number of specific cultures, each with their own casing rules
Used to compare text using culture-sensitive sort rules and the current culture. Case of the texts is ignored when comparing.
For more information about comparison types, please see StringComparison.
TODO: Consider moving sections below into the StringComparison Data Type documentation and removed from this page
Ordinal
TODO:
When to use? If not sure what to choose?
Ordinal sort rules
notes about ordinal and a worked through example
Ordinal Ignore Case
TODO:
When to use? If not sure what to choose?
Link to Ordinal sort rules, only difference is that it doesn’t consider casing when comparing characters
notes about ordinal ignore case and a worked through example
Invariant Culture
TODO:
When to use? If not sure what to choose?
Link to Culture -> Invariant Culture
Invariant Culture rules
notes about invariant culture and a worked through example
Invariant Culture Ignore Case
TODO:
When to use? If not sure what to choose?
Link to Culture -> Invariant Culture
Link to Invariant Culture sort rules, only difference is that it doesn’t consider casing when comparing characters
notes about invariant culture ignore case and a worked through example
Current Culture
TODO:
When to use? If not sure what to choose?
Link to Culture -> Current Culture
Current Culture rules
notes about current culture and a worked through example
Current Culture Ignore Case
TODO:
When to use? If not sure what to choose?
Link to Culture -> Current Culture
Link to Current Culture sort rules, only difference is that it doesn’t consider casing when comparing characters
notes about current culture ignore case and a worked through example
Remarks
Known Limitations
TODO
See Also
Related Concepts
TODO
Related Data Types
TODO
Related Blocks
TODO
External Documentation
TODO
6.1.2.11.7 - Formatting
Information regarding text formatting.
Formatting
Summary
TODO:
What formatting is
How to format text
Blocks
Expression
How does text formatting use DateTime Formatting and Number Formatting?
Link to Working With -> Date and Time -> Date and Time Formatting
Link to Working With -> Number -> Number Formatting
Using Blocks
TODO:
Explain that blocks can be used - maybe with examples or link to examples within the block documentation
Convert Object to Text
Format Text with Value
Format Text with Values
Using Expressions
TODO: How to format using an expression
String Interpolation
TODO:
mention that convert object to text is close to behaviour of string interpolation, but not everything is covered - e.g. no expression support or indexing - recommendation is to use string.interpolation inline as more powerful and saves block licensing
Format Providers
TODO:
what are they
ways of creating
CultureInfo.InvariantCulture
CultureInfo.CurrentCulture
new CultureInfo("")
new CultureInfo(“en-GB”)
Format Templates
TODO:
Find C# link
Talk about what a template is and how format parameters are used (e.g. "{0}")
curly brackets need to be escaped when using the $ and $@ prefixes
Include information about any builtin snippets for each regex
A character class matches any of a set of characters. Character classes include the language elements listed in the following table.
Syntax
Description
Pattern
Matches
[characters]
Matches any character found in characters.
[oz]
o in Cortex
[^characters]
Matches any character not found in characters.
[^oz]
C, r, t, e, x in Cortex
[first-last]
Matches any character in the range of characters from first to last.
[A-C]
C in Cortex
.
Wildcard. Matches any character except \n.
C.r
Cor in Cortex
\p{category}
Matches any character in a category of Unicode characters, specified by category. To see what you can use for category, please check the supported Unicode general categories and the supported named blocks.
\p{Lu}
C in Cortex
\P{category}
Matches any character not in a category of Unicode characters, specified by category. To see what you can use for category, please check the supported Unicode general categories, and the supported named blocks.
\P{Lu}
o, r, t, e, x in Cortex
\w
Matches any letter, decimal digit, or an underscore.
\w
C, o, r, t, e, x in Cortex !
\W
Matches any character except a letter, decimal digit, or an underscore.
\W
! in Cortex !
\s
Matches any white-space character.
\w\s
x in Cortex !
\S
Matches any character except a white-space character.
Include information about any builtin snippets for each regex
The following table lists the character escapes supported by regular expressions in .NET.
Syntax
Description
Pattern
Matches
\r
Matches a carriage return.
\r\n(\w+)
\r\nCortex in \r\nCortex with\na new line
\n
Matches a newline.
\r\n(\w+)
\r\nCortex in \r\nCortex with\na new line
\t
Matches a tab.
(\w+)\t
Cortex1\t, Cortex2\t in Cortex1\tCortex2\t
[\b]
Matches a backspace. Note that it must be enclosed in brackets to have this meaning.
[\b]{3,}
\b\b\b\b in \b\b\b\b
\f
Matches a form feed.
[\f]{2,}
\f\f\f in \f\f\f
\e
Matches an escape.
\e
\x001B in \x001B
\v
Matches a vertical tab.
[\v]{2,}
\v\v\v in \v\v\v
\a
Matches the bell character.
\a
\u0007 in Cortex ‘\u0007’
\octal
Matches a character, where octal is the octal representation of that character.
\w\040\w
x C in Cortex Cortex
\xhex
Matches a character, where hex is the two-digit hexadecimal representation of that character.
\w\x20\w
x C in Cortex Cortex
\uunicode
Matches a Unicode character, where unicode is the four digit hexadecimal representation of that Unicode character.
\w\u0020\w
x C in Cortex Cortex
\ccharacter
Matches an ASCII control character specified by character.
\cC
\x0003 in \x0003
Quantifiers
TODO:
Include information about any builtin snippets for each regex
A quantifier specifies how many instances of the previous element (which can be a character, a group, or a character class) must be present in the input string for a match to occur. Quantifiers include the language elements listed in the following table.
Syntax
Description
Pattern
Matches
*
Matches previous element zero or more times.
co*rtex
crtex, cortex, coortex, coooortex in crtex cortex coortex coooortex
+
Matches previous element one or more times.
co+rtex
cortex, coortex, coooortex in crtex cortex coortex coooortex
?
Matches previous element zero or one times.
co?rtex
crtex, cortex in crtex cortex coortex coooortex
{n}
Matches previous element exactly n times.
co{2}rtex
coortex in crtex cortex coortex coooortex
{n,}
Matches previous element at least n times.
co{2,}rtex
coortex, coooortex in crtex cortex coortex coooortex
{n,m}
Matches previous element at least n times and at most m times.
co{1,2}rtex
cortex, coortex in crtex cortex coortex coooortex
*?
Matches previous element zero or more times, but as few times as possible.
cort(ex)*?
cort in cortexexex
+?
Matches previous element one or more times, but as few times as possible.
cort(ex)+?
cortex in cortexexex
??
Matches previous element zero or one time, but as few times as possible.
cort(ex)??
cort in cortexexex
{n,}?
Matches previous element at least n times, but as few times as possible.
cort(ex){2,}?
cortexex in cortexexex
{n,m}?
Matches previous element at least n times and at most m times, but as few times as possible.
cort(ex){1,3}?
cortex in cortexexex
Anchors
TODO:
Include information about any builtin snippets for each regex
Anchors cause a match to succeed or fail depending on the current position in the string.
Syntax
Description
Pattern
Matches
^
Matches the beginning of the input.
^\w{3}
Cor in Cortex
$
Matches the end of the input, or the point before a final \n at the end of the input.
\w{3}$
tex in Cortex
\A
Matches the beginning of the input. Identical to ^, except it is unaffected by the multi-line option.
\A\w{3}
Cor in Cortex
\z
Matches the end of the input, without exception.
\w{3}\z
tex in Cortex
\Z
Matches the end of the input, or the point before a final \n at the end of the input. Identical to $, except it is unaffected by the multi-line option.
\w{3}\Z
tex in Cortex
\G
Matches the point that the previous match ended. Used to find contiguous matches.
\G\D*\s
Cortex , reads in Cortex reads 7 files
\b
Matches any word boundary. Specifically, any point between a \w and a \W.
\b\w+\s\w+\b
Cortex reads, Cortex writes in Cortex reads Cortex writes
\B
Matches any point that is not a word boundary. Specifically, any point not between a \w and a \W.
\Brt\w*\b
rtex, rtex in Cortex reads Cortex writes
Grouping Constructs
TODO:
Include information about any builtin snippets for each regex
Grouping constructs delineate sub-expressions of a regular expression and typically capture sub-strings of an input string. Grouping constructs include the language elements listed in the following table.
Syntax
Description
Pattern
Matches
(subpattern)
Captures subpattern as an unnamed group.
(\w)\1
oo in Coortex
(?<name>subpattern)
Captures subpattern as a named group specified by name.
(?<double>\w)\k<double>
oo in Coortex
(?<name-previous>subpattern)
Balancing group definition. This allows nested constructs to be matched, such as parentheses or HTML tags. The previously defined group to balance against is specified by previous. Captures subpattern as a named group specified by name, or name can be omitted to capture as an unnamed group.
<span>Cortex this is included</span>, <span>Cortex this is included too</span> in not included <span>Cortex this is included</span> not included either <span>Cortex this is included too</span>
(?:subpattern)
Non-capturing group. Allows the use of parentheses without subpattern being captured into a group.
Cortex\s(?:include)?
Cortex include, Cortex in Cortex include Cortex not include
(?enabled-disabled:subpattern)
Allows subpattern to be matched with different options than the rest of the pattern. Any inline option characters in enabled or disabled will enable or disable specific options, respectively. To see what inline option characters are available, please check the regular expressions options.
(?i:c|v)(ortex)
cortex, Cortex, Vortex in cortex Cortex Vortex CORTEX
(?=subpattern)
Zero-width positive look-ahead assertion. Continues matching only if subpattern matches on the right.
\w+(?=ex\b)
Cort, Vort in Cortex Vortex Balloon
(?!subpattern)
Zero-width negative look-ahead assertion. Continues matching only if subpattern does not match on the right.
\b\w+\.(?!exe)\w+\b
cortex.jpg, cortex.html in cortex.jpg cortex.html .*.html cortex.exe
(?<=subpattern)
Zero-width positive look-behind assertion. Continues matching only if subpattern matches on the left.
(?<=\(\$\))\w+
variable, 22 in ($)variable ($)22 ($)–
(?<!subpattern)
Zero-width negative look-behind assertion. Continues matching only if subpattern does not match on the left.
\b\w(?<![aeiou])\w*
Cortex, words, which, does, not, start, with, vowel, like in Cortex words which does not start with a vowel like all
(?>subpattern)
Prevents backtracking over subpattern, which can improve performance.
[cv](?>o+r+)
cor, coor, vor in cortex coortex vortex gortex
Back-reference Constructs
TODO:
Include information about any builtin snippets for each regex
A back-reference allows a previously matched sub-expression to be identified subsequently in the same regular expression. The following table lists the back-reference constructs supported by regular expressions in .NET.
Syntax
Description
Pattern
Matches
\number
Matches the value of a previously captured group, specified by number.
\b(\w)\w*\1\b
xcortex, that in Finds all words like xcortex that start and end with the same letter
\k<name>
Matches the value of a previously captured named group, specified by name.
(?<punctuation>\p{P})\w+\k<punctuation>
!cortex!, ?cortex? in !cortex! ?cortex? XcortexX
Alternation Constructs
TODO:
Include information about any builtin snippets for each regex
Alternation constructs changes a regular expression to enable either/or matching. These constructs include the language elements listed in the following table.
Syntax
Description
Pattern
Matches
|
Functions as a logical or. Matches any elements it separates.
(c|v)ortex
cortex, vortex in cortex vortex xortex
(?(subpattern)yes|no)
Treats subpattern as a zero-width assertion to check if it matches. If so, attempts to match with the yes subpattern. Otherwise, tries the no subpattern. The |no part is optional.
\b(?(\w+tez\b)\w{3}|cortex)
cortex, cor in cortex cortez vortex
(?(group)yes|no)
Checks if a previously defined group was successfully captured, specified by group, which can be a number or a name for a named group. If so, attempts to match with the yes subpattern. Otherwise, tries the no subpattern. The |no part is optional.
(?(<quoted>\(\$\)))\w+|'\w+'
cortex, ‘cortex’ in ($)cortex ‘cortex’
Substitutions
TODO:
Include information about any builtin snippets for each regex
Substitutions are regular expression language elements supported in replacement patterns.
Syntax
Description
Pattern
Replacement
Result
$number
Substitutes the value of a group, specified by number.
\b(\w+)(\s)(\w+)\b
$3$2$1
Cortex Great becomes Great Cortex
${name}
Substitutes the value of a named group, specified by name.
\b(?<word1>\w+)(\s)(?<word2>\w+)\b
${word2} ${word1}
Cortex Great becomes Great Cortex
$$
Substitutes the $ character.
\b(dollar)
$$
(dollar)name becomes ($)name
$&
Substitutes the entire match.
\w+
\*\*$&\*\*
Cortex becomes **Cortex**
$`
Substitutes all input text found before the match.
Connects to a data source (e.g. SQL Server) using the specified Connection Details, and executes a Command (e.g. SELECT * FROM Table), returning the Result.
Close Connection can be specified to choose whether the connection to the data source is closed or is kept open for use on subsequent Execute Command blocks.
Examples
Selecting Rows
This example will select all rows and columns from a connected SQL Server data source which have an Id less than 3, saving the rows to the Result.
A QueryCommand is used throughout this example to select data from the data source, however, both an Command or Commands could also be used to the same effect.
The data source contains a Table with the following rows and columns before the command is executed:
Selecting all rows and columns that have an Id less than 3 from Table using a QueryCommand results in the variable ($)Result being updated to the following:
This example will insert a new row into a connected SQL Server data source, saving the number of rows inserted to the Result.
A NonQueryCommand is used throughout this example to insert data into the data source, however, both an Command or Commands could also be used to the same effect.
The data source contains a Table with the following rows and columns before the command is executed:
This example will update all rows on a connected SQL Server data source which have an Id less than 3, saving the number of rows updated to the Result.
A NonQueryCommand is used throughout this example to update data in the data source, however, both an Command or Commands could also be used to the same effect.
The data source contains a Table with the following rows and columns before the command is executed:
($)Command, with value {"CommandText": "UPDATE Table SET FirstColumn = \"Updated\" WHERE Id < @UpdateParameter", "Parameters": { "UpdateParameter": 3 } }
In this example ($)Command has been set using the following Expression:
new NonQueryCommand("UPDATE Table SET FirstColumn = \"Updated\" WHERE Id < @UpdateParameter", new {UpdateParameter = 3})
This example will delete all rows on a connected SQL Server data source which have an Id less than 3, saving the number of rows deleted to the Result.
A NonQueryCommand is used throughout this example to delete data in the data source, however, both an Command or Commands could also be used to the same effect.
The data source contains a Table with the following rows and columns before the command is executed:
This example will select the maximum Id value from a connected SQL Server data source, saving the value of the function to the Result.
A QueryCommand is used throughout this example to select the maximum Id value from the data source, however, both an Command or Commands could also be used to the same effect.
The data source contains a Table with the following rows and columns before the command is executed:
Selecting the maximum Id value from Table using a QueryCommand results in the variable ($)Result being updated to the following:
[{"":3}]
Note that the AS keyword can be used to give aliases to results, for example the CommandText "SELECT Max(Id) AS MaxId FROM Table;" would have resulted in the variable ($)Result being updated to [ { "MaxId": 3 } ]; the AS keyword also allows for Using Multiple Functions.
Using Multiple Functions
This example will select the maximum Id value as MaxId and the minimum Id value as MinId from a connected SQL Server data source, saving the values of the functions to the Result.
A QueryCommand is used throughout this example to select the maximum Id value as MaxId and the minimum Id value as MinId from the data source, however, both an Command or Commands could also be used to the same effect.
The data source contains a Table with the following rows and columns before the command is executed:
Selecting the maximum Id value as MaxId and the minimum Id value as MinId from Table using a QueryCommand results in the variable ($)Result being updated to the following:
[{"MaxId":3,"MinId":1}]
Executing Multiple Commands (Safe)
This example will select, insert, update and delete from a connected SQL Server data source, using a parameterised command. The result of each command will be saved to the result.
An Commands is used throughout this example, as it is the only type of Command that allows you to execute and return the results of multiple commands.
The data source contains a Table with the following rows and columns before the command is executed:
($)Command, with value {"CommandText": "SELECT * FROM Table WHERE Id < @SelectParameter; INSERT INTO Table (FirstColumn, SecondColumn) VALUES (@InsertParameter1, @InsertParameter2); UPDATE Table SET FirstColumn = \"Updated\" WHERE Id < @UpdateParameter; DELETE FROM Table WHERE Id < @DeleteParameter; SELECT * FROM Table", "Parameters": { "SelectParameter": 3, InsertParameter1 = \"FirstColumn4\", InsertParameter2 = \"SecondColumn4\", "UpdateParameter": 3, "DeleteParameter": 3 }}
In this example ($)Command has been set using the following Expression:
new Commands("SELECT * FROM Table WHERE Id < @SelectParameter; INSERT INTO Table (FirstColumn, SecondColumn) VALUES (@InsertParameter1, @InsertParameter2); UPDATE Table SET FirstColumn = \"Updated\" WHERE Id < @UpdateParameter; DELETE FROM Table WHERE Id < @DeleteParameter; SELECT * FROM Table", new {SelectParameter = 3, InsertParameter1 = "FirstColumn4", InsertParameter2 = "SecondColumn4", UpdateParameter = 3, DeleteParameter = 3})
The first item of ($)Result represents the rows selected by the first select statement (SELECT * FROM Table WHERE Id < @SelectParameter).
The second item of ($)Result indicates that 1 row has been inserted into Table (INSERT INTO Table (FirstColumn, SecondColumn) VALUES (@InsertParameter1, @InsertParameter2)).
The third item of ($)Result indicates that 2 rows have been updated in Table (UPDATE Table SET FirstColumn = \"Updated\" WHERE Id < @UpdateParameter).
The fourth item of ($)Result indicates that 2 rows have been deleted in Table (DELETE FROM Table WHERE Id < @DeleteParameter).
The fifth item of ($)Result represents the rows selected by the second select statement (SELECT * FROM Table).
This example will select, insert, update and delete from a connected SQL Server data source, using String Interpolation instead of parameters. The result of each command will be saved to the result.
Warning
This example inserts data directly into the Command instead of using parameters. This means the SQL in this example is susceptible to SQL Injection and it is advised to use parameters to insert data into a command instead.
($)Command, with value {"CommandText": "SELECT * FROM Table WHERE Id < 3; INSERT INTO Table (FirstColumn, SecondColumn) VALUES (\"FirstColumn1\", \"SecondColumn2\"); UPDATE Table SET FirstColumn = \"Updated\" WHERE Id < 3; DELETE FROM Table WHERE Id < 3; SELECT * FROM Table", "Parameters": null}
In this example ($)Command has been set using the following Expression:
new Commands($"SELECT * FROM Table WHERE Id < {($)SelectParameter}; INSERT INTO Table (FirstColumn, SecondColumn) VALUES ({($)InsertParameter1}, {($)InsertParameter2}); UPDATE Table SET FirstColumn = \"Updated\" WHERE Id < {($)UpdateParameter}; DELETE FROM Table WHERE Id < {($)DeleteParameter}; SELECT * FROM Table", null)
The first item of ($)Result represents the rows selected by the first select statement (SELECT * FROM Table WHERE Id < @SelectParameter).
The second item of ($)Result indicates that 1 row has been inserted into Table (INSERT INTO Table (FirstColumn, SecondColumn) VALUES (@InsertParameter1, @InsertParameter2)).
The third item of ($)Result indicates that 2 rows have been updated in Table (UPDATE Table SET FirstColumn = \"Updated\" WHERE Id < @UpdateParameter).
The fourth item of ($)Result indicates that 2 rows have been deleted in Table (DELETE FROM Table WHERE Id < @DeleteParameter).
The fifth item of ($)Result represents the rows selected by the second select statement (SELECT * FROM Table).
The Command executed on the connected data source. There are multiple Command Types that can be used, each with a different purpose:
Command: Parses a single statement provided in the commandText, determining how the statement should be executed against the data source. If the commandText is a Query Statement the rows retrieved from the data source will be returned, otherwise if the commandText is a Non Query Statement the number of rows affected will be returned.
Commands: Parses single or multiple statements provided in the commandText, determining how each statement should be executed against the data source. If a Query Statement is executed rows retrieved from the data source are added as an entry of the result, If a Non Query Statement is executed the number of rows affected is added as an entry of the result.
QueryCommand: Executes the given commandText as a Query Statement, returning the rows retrieved from the data source.
Command with value {"CommandText": "", "Parameters": null}
Connection Details
The Connection Details object that includes all of the information required to connect to a data source, including:
Connection String - must be provided in order to connect to a data source. The Connection String is formatted differently depending on the type of data source that is being connected to, please see Working with Data Sources for more information.
For a list of currently supported connection details, please see ConnectionDetails
Note it is recommended to use a Variable for Connection Details when it will be used across multiple Execute Command blocks, as using a variable will allow for reuse of the same connection. Using a Literal to set the Connection Details will cause the connection to only be used once.
SqlServerConnectionDetails with value {"ConnectionString": "Server=localhost;Database=YourDatabase;Trusted_Connection=true;"}
Close Connection
Close Connection can be specified to choose whether the connection to the data source is closed or is kept open for use on subsequent Execute Command blocks, this defaults to false if left blank, please see Closing Connections for more information.
Depending on the type of Command, the data returned within the Result will vary. Please see Command Types for more information on what data will be returned by each type.
Thrown when an invalid connection string has been supplied (e.g. The connection string contains an invalid argument "NotAnArgument = False").
Thrown when a required connection string argument has not been supplied (e.g. The server requires encryption and the connection string contains "Encrypt=False").
Thrown when an Command contains multiple statements.
Remarks
Command Types
There are multiple types of Command that can be used, each with a different purpose:
Command
A Command parses a single statement provided in the commandText, determining how the statement should be executed against the data source. If the commandText is a Query Statement the rows retrieved from the data source will be returned, otherwise if the commandText is a Non Query Statement the number of rows affected will be returned.
A Commands parses single or multiple statements provided in the commandText, determining how each statement should be executed against the data source. If a Query Statement is executed rows retrieved from the data source are added as an entry of the result, If a Non Query Statement is executed the number of rows affected is added as an entry of the result.
Note that the Commands should not be used for commands that have dependency between their statements (e.g. Cursors and Variables). Please see Complex Commands for more information on how to deal with these.
Note use a QueryCommand for commands that have dependency between their statements (e.g. Cursors and Variables) and return data from the data source. Please see Complex Commands for more information.
NonQueryCommand
A NonQueryCommand executes the given commandText as a Non Query Statement, returning the number of rows affected from the data source. If the command contains multiple statements, the sum of all the results will be returned.
Note use a NonQueryCommand for commands that have dependency between their statements (e.g. Cursors and Variables) and return the number of rows affected. Please see Complex Commands for more information.
Statement Types
There are two categories of statements Query and Non Query.
Query Statements
Query Statements are used to retrieve data from a data source, for example selecting all rows from a table in a database, Query Statements return the data selected by the Statement as a List<Structure> when used in an Command, an Commands, or a QueryCommand. If a Query Statement is used in a NonQueryCommand-1 will be returned as Query Statements do not affect rows.
A Query Statement can use any object as a parameter. Objects that derive from Array or IEnumerable can only be used for clauses that accept list values (e.g. IN, ANY, ALL), if they are used in other clauses the block will throw a CommandException.
Non Query Statements
Non Query Statements are used to manipulate the data within a data source, for example deleting all rows from a table in a database, Non Query Statements return the number of rows affected by the Statement as an Int32 value when used in an Command, an Commands, or a NonQueryCommand. If a Non Query Statement is used in a QueryCommandnull will be returned as Non Query Statements do not return data.
Examples of Non Query Statements can be found here:
A Non Query Statement can use any object as a parameter. If an object that derives from Array or IEnumerable is used, the Non Query Statement will be executed for each item in the Array or IEnumerable and the sum of all the results will be returned.
Parameterised Commands
It is recommended to always use parameterised commands as they prevent SQL Injection attacks by ensuring the parameters are sanitised before the Command is executed.
The @ symbol denotes a parameter within the CommandText (e.g. "SELECT * FROM Table WHERE Name = @Parameter"). An example of using parameters can be found in Executing Multiple Commands (Safe), whereas, an example of inserting variables into a statement without parameters can be found in Executing Multiple Commands (Unsafe)
Query Statements can use any object as a parameter. Objects that derive from Array or IEnumerable can only be used for clauses that accept list values (e.g. IN, ANY, ALL), if they are used in other clauses the block will throw a CommandException.
Non Query Statements can use any object as a parameter. If an object that derives from Array or IEnumerable is used, the Non Query Statement will be executed for each item in the Array or IEnumerable and the sum of all the results will be returned.
For both Query Statements and Non Query Statements, an SqlException is thrown if a parameter is missing from the Command and the CommandText contains a parameter (e.g. {"CommandText": "SELECT * FROM Table WHERE Name = @Parameter", "Parameters": {"IncorrectParameter": 0}}).
Complex Commands
Complex commands (e.g. Cursors and Variables) that contain dependency between their statements cannot be used with Commands, as the parsing performed by the block will cause each statement of CommandText to be run individually instead of running the CommandText as a whole.
For statements with this type of dependency use either QueryCommand or NonQueryCommand, depending on whether data from the data source or the number of rows affected is returned.
Connection Strings
A connection string must be provided within the Connection Details in order to connect to a data source. The connection string is formatted differently depending on the type of data source, please see Working with Data Sources for more information.
Please see Working with Data Sources for a list of supported data sources and how to construct valid connection strings for them.
Opening Connections
The Execute Command block automatically handles creating and opening connections for the specified Connection Details using the following rules:
If a connection does not exist, a new connection will be created, opened and used when the block runs.
If a connection already exists but is closed, the connection will be opened and used when the block runs.
If a connection already exists and is open, the connection will used the block runs.
If a Variable is used to pass in the Connection Details it can be used to keep the connection alive across multiple Execute Command blocks as long as Close Connection is set to false. Keeping the connection open helps increase the performance of the block due to the subsequent blocks not having to spend resources creating and opening connections for each execution.
If a Literal or an Expression is used to create the Connection Details a new connection will always be made when the Execute Command block runs and if Close Connection is set to false the connection will be closed automatically at some point after the block finishes and before the flow ends.
For information on how to explicitly close a connection, please see Closing Connections.
Closing Connections
Connections can be explicitly closed by setting Close Connection to true. This causes the connection to be closed after the Command has been executed.
If a Variable is used to pass in the Connection Details and Close Connection is set to false the connection will be closed when the Variable goes out of scope or the flow ends, whichever happens first. For more information about variables and scope, please see Variables.
If a Literal or an Expression is used to create the Connection Details and Close Connection is set to false the connection will be closed automatically at some point after the Execute Command block finishes and before the flow ends.
For information on how to open a connection, please see Opening Connections.
Why does the Result property return a dynamic data type?
The decision for the Result to return a dynamic data type rather than a specific type, was to avoid users having to cast the Result to its correct type to be able to use all of its properties.
As a result, any issues with using the Result (i.e. trying to access a property it does not have) will not be reported as messages when trying to debug the flow; they will only be discovered when the flow execution reaches the part of the flow with the issue.
If it is desirable to have any issues reported as messages when trying to debug the flow, the user can cast the Result to its correct type.
Known Limitations
When using a Parameterised Command to execute a stored procedure, it is not possible to write back to output parameters.
6.3.2 - Date & Time
Blocks related to working with Date and Time.
6.3.2.1 - Add Time Period
Add a time period (Years, Months, Days, Hours, Minutes, Seconds and Milliseconds) to a date time.
Adding 1 year, 1 month, 1 day, 1 hour and 30 minutes to 2021-01-01T00:00:00+00:00 will result in the variable ($)DateTime being updated. Its text representation will be in the ISO 8601 Standard, which can be seen below:
"2022-02-02T01:30:00+00:00"
Add a negative Time Period
This example will add -1 year to 2021-01-01T00:00:00+00:00.
Adding -1 year from 2021-01-01T00:00:00+00:00 will result in 1 year being subtracted and the variable ($)DateTime being updated. Its text representation will be in the ISO 8601 Standard, which can be seen below:
Time Period can have positive and negative components where components are:
Years
Months
Days
Hours
Minutes
Seconds
Milliseconds
When adding a Time Period, the block will first add years, followed by months, days, hours, minutes, seconds and finally milliseconds.
When adding months, if the current day component is greater than the last day in the resultant month, it will update the day to the last day for that month (e.g. adding one month onto 2021-01-31T23:59:59+00:00 will equate to 2021-02-28T23:59:59+00:00).
When adding a Time Period, the block will first add years, followed by months, days, hours, minutes, seconds and finally milliseconds.
Addition of Months
When adding months to the Date Time, if the current day component is greater than the last day in the resultant month, it will update the day to the last day for that month (e.g. adding one month onto 2021-01-31T23:59:59+00:00 will equate to 2021-02-28T23:59:59+00:00).
Daylight Savings
This block copes with UTC time offsets but does not know anything about which time zone the Date Time represents; as a result it cannot take daylight savings into account as these are related to time zones rather than UTC time offsets.
Format Template can be specified to define the format the Date Time should be converted to (e.g. "dd/MM/yyyy").
Format Provider can be specified to define the cultural rules used to control the formatting (e.g. new CultureInfo("en-US") will apply American English rules to the formatting).
Examples
ISO 8601 Standard Format
This example will convert a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset) to the ISO 8601 Standard format (i.e. "yyyy-MM-ddTHH:mm:ss.fffffffzzz").
($)Text is a variable that will be set to a String value
Result
Converting a Date Time representing midnight on 31st December 2021 (with a 0 UTC time offset and without specifying any format template or provider) will result in the variable ($)Text being updated to the following ISO 8601 Standard text representation:
"2021-12-31T00:00:00.0000000+00:00"
Default format for Invariant Culture
This example will convert a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset) to the default format for Invariant Culture (i.e. "MM/dd/yyyy HH:mm:ss zzz").
($)Text is a variable that will be set to a String value
Result
Converting a Date Time representing midnight on 31st December 2021 (with a 0 UTC time offset and without a format template), but specifying Invariant Culture text representation, will result in the variable ($)Text being updated to the following:
"12/31/2021 00:00:00 +00:00"
Full Date Long Time format for Invariant Culture
This example will convert a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset) to the Full Date Long Time format for Invariant Culture (i.e. "dddd, dd MMMM yyyy HH:mm:ss").
($)Text is a variable that will be set to a String value
Result
Converting a Date Time representing midnight on 31st December 2021 (with a 0 UTC time offset), and specifying the Full Date Long Time format for Invariant Culture, will result in the variable ($)Text being updated to the following:
"Friday, 31 December 2021 00:00:00"
Default format for American English (“en-US”)
This example will convert a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset) to the default format for American English "en-US" (i.e. "MM/d/yyyy h:m:s tt zzz").
($)Text is a variable that will be set to a String value
Result
Converting a Date Time representing midnight on 31st December 2021 (with a 0 UTC time offset and without a format template), but specifying an American English "en-US" text representation, will result in the variable ($)Text being updated to the following:
"12/31/2021 12:00:00 AM +00:00"
Full Date Long Time format for American English (“en-US”)
This example will convert a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset) to the Full Date Long Time format for American English "en-US" (i.e. "dddd, MMMM d, yyyy h:m:s tt").
($)Text is a variable that will be set to a String value
Result
Converting a Date Time representing midnight on 31st December 2021 (with a 0 UTC time offset), and specifying the Full Date Long Time format for American English "en-US", will result in the variable ($)Text being updated to the following:
Format Template can be specified to define the format the Date Time should be converted to (e.g. "dd/MM/yyyy" -> "31/12/2021").
If Format Template contains valid format specifiers (e.g. "dd" for 2 digit day representation), they will be subsitituted based on the Date Time; characters that are not format specifiers will be passed through as literal text.
If Format Template is not specified, null or empty (i.e. ""), the default format template of the specified Format Provider is used. If Format Provider is also not specified or null the ISO 8601 Standard format will be used (i.e. "yyyy-MM-ddTHH:mm:ss.fffffffzzz").
Format Provider can be specified to define the cultural rules used to control the formatting (e.g. new CultureInfo("en-US") will apply American English rules to the formatting.).
If Format Provider is not specified or null, CultureInfo.InvariantCulture will be used; CultureInfo.InvariantCulture is associated with the English language but not with any country/region. For more information, please see Invariant Culture rules.
If Format Template is not specified, null or empty (i.e. ""), the default format template of the specified Format Provider is used. If Format Provider is also not specified or null the ISO 8601 Standard format will be used (i.e. "yyyy-MM-ddTHH:mm:ss.fffffffzzz").
Null Format Provider
If Format Provider is not specified or null, CultureInfo.InvariantCulture will be used; CultureInfo.InvariantCulture is associated with the English language but not with any country/region. For more information, please see Invariant Culture rules.
Format Template can be specified to explicity define the format of the Text (e.g. "dd/MM/yyyy").
Format Provider can be specified to define the cultural rules used to control the conversion (e.g. new CultureInfo("en-US") will apply American English rules to the conversion).
($)DateTime is a variable that will be set to a DateTimeOffset value
Result
Converting "2021-12-31T00:00:00.0000000+00:00" to a Date Time (without specifying any format template or provider) will result in the variable ($)DateTime being updated to a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset). Its text representation will be in the ISO 8601 Standard, which can be seen below:
"2021-12-31T00:00:00.0000000+00:00"
Default format for Invariant Culture
Default format for Invariant Culture is "MM/dd/yyyy HH:mm:ss zzz".
This example will convert "12/31/2021 00:00:00 +00:00" to a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset).
($)DateTime is a variable that will be set to a DateTimeOffset value
Result
Converting "12/31/2021 00:00:00 +00:00" to a Date Time without specifying a format template but specifying Invariant Culture, will result in the variable ($)DateTime being updated to a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset). Its text representation will be in the ISO 8601 Standard, which can be seen below:
"2021-12-31T00:00:00.0000000+00:00"
Full Date Long Time format for Invariant Culture
Full Date Long Time format for Invariant Culture is "dddd, dd MMMM yyyy HH:mm:ss".
This example will convert "Friday, 31 December 2021 00:00:00" to a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset).
($)DateTime is a variable that will be set to a DateTimeOffset value
Result
Converting "Friday, 31 December 2021 00:00:00" to a Date Time specifying the Full Date Long Time format for Invariant Culture, will result in the variable ($)DateTime being updated to a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset). Its text representation will be in the ISO 8601 Standard, which can be seen below:
"2021-12-31T00:00:00.0000000+00:00"
Default format for American English (“en-US”)
Default format for American English (“en-US”) is "MM/d/yyyy h:m:s tt zzz".
This example will convert "12/31/2021 12:00:00 AM +00:00" to a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset).
($)DateTime is a variable that will be set to a DateTimeOffset value
Result
Converting "12/31/2021 12:00:00 AM +00:00" to a Date Time without specifying a format template but specifying American English "en-US", will result in the variable ($)DateTime being updated to a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset). Its text representation will be in the ISO 8601 Standard, which can be seen below:
"2021-12-31T00:00:00.0000000+00:00"
Full Date Long Time format for American English (“en-US”)
Full Date Long Time format for American English (“en-US”) is "dddd, MMMM d, yyyy h:m:s tt".
This example will convert "Friday, December 31, 2021 12:00:00 AM" to a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset).
($)DateTime is a variable that will be set to a DateTimeOffset value
Result
Converting "Friday, December 31, 2021 12:00:00 AM" to a Date Time specifying the Full Date Long Time format for American English "en-US", will result in the variable ($)DateTime being updated to a Date Time representing midnight on 31st December 2021 (with 0 UTC time offset). Its text representation will be in the ISO 8601 Standard, which can be seen below:
Format Template can be specified to define the format the Text is in (e.g. "dd/MM/yyyy").
If Format Template does not contain any valid format specifiers (e.g. "ww/ww/wwww") and the text exactly matches the Format Template (e.g. "ww/ww/wwww"), then Date Time is set to a DateTimeOffset value that represents the current Date and Time.
If Format Template is not specified, null or empty (i.e. ""), the ISO 8601 Standard format will be used for the conversion (i.e. "yyyy-MM-ddTHH:mm:ss.fffffffzzz").
Format Provider can be specified to define the cultural rules used to control the conversion (e.g. new CultureInfo("en-US") will apply American English rules to the conversion).
If Format Provider is not specified or null, CultureInfo.InvariantCulture will be used; CultureInfo.InvariantCulture is associated with the English language but not with any country/region. For more information, please see Invariant Culture rules.
Thrown when Format Template does not contain any valid specifiers (e.g. "ww/ww/wwww").
Thrown when Format Template contains non-specifier characters, and Text does not match the characters exactly (e.g. "01/10/2021 12:00" and "dd/ww/yyyy hh:mm" will throw, but "01/ww/2021 12:00" and "dd/ww/yyyy hh:mm" does not).
If Format Template is not specified, null or empty (i.e. ""), the ISO 8601 Standard format will be used for the conversion (i.e. "yyyy-MM-ddTHH:mm:ss.fffffffzzz").
If Format Provider is not specified or null, CultureInfo.InvariantCulture will be used; CultureInfo.InvariantCulture is associated with the English language but not with any country/region. For more information, please see Invariant Culture rules.
6.3.2.3 - Get Date Time
Get the current date time or parts of a date time (i.e. Year, Month, Day).
($)DateTime is a variable that will be set to a DateTimeOffset value
Result
Getting the current Date Time will result in the variable ($)DateTime being set to a DateTimeOffset representing the current Date Time (including a UTC time offset). Its text representation will be in the ISO 8601 Standard, which can be seen below:
"2021-11-05T08:48:08.0307614+00:00"
Properties
Date Time
The current Date Time including a UTC time offset.
Its text representation will be in the ISO 8601 Standard (e.g. 2021-11-05T08:48:08.0307614+00:00).
($)Component is a variable that will be set to a dynamic value
Result
Getting the LocalDateTime (GMT) of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to a DateTime value. Its text representation will be in the ISO 8601 Standard, which can be seen below:
"2021-12-31T10:00:00+00:00"
UtcDateTime
This example will get the UTCDateTime of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the UTCDateTime of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to a DateTime value. Its text representation will be in the ISO 8601 Standard, which can be seen below:
"2021-12-31T10:00:00Z"
Date
This example will get the Date component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the Date component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to a DateTime value. Its text representation will be in the ISO 8601 Standard, which can be seen below:
"2021-12-31T00:00:00"
Time
This example will get the Time component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the Time component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to the following TimePeriod value:
($)Component is a variable that will be set to a dynamic value
Result
Getting the Year component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to the following Int32 value:
2021
Month
This example will get the Month component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the Month component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to the following Int32 value:
12
Day
This example will get the Day component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the Day component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to the following Int32 value:
31
Hour
This example will get the Hour component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the Hour component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to the following Int32 value:
5
Minute
This example will get the Minute component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the Minute component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to the following Int32 value:
0
Second
This example will get the Second component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the Second component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to the following Int32 value:
0
Millisecond
This example will get the Millisecond component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the Millisecond component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to the following Int32 value:
0
Offset
This example will get the Offset component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the Offset component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to the following TimeSpan value with the following text representation:
"-5:00:00"
DayOfYear
This example will get the DayOfYear component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the DayOfYear component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to the following Int32 value:
365
DayOfWeek
This example will get the DayOfWeek component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset).
($)Component is a variable that will be set to a dynamic value
Result
Getting the DayOfWeek component of a Date Time representing 5am on 31st December 2021 (with -5 UTC time offset), will result in the variable ($)Component being updated to the following DayOfWeek value:
Why does the Component property return a dynamic data type?
The decision for Component to return a dynamic data type rather than an Object, was to avoid users having to cast the component to its correct type to be able to use all of its properties.
As a result, any issues with using the Component (i.e. trying to access a property it does not have) will not be reported as messages when trying to debug the flow; they will only be discovered when the flow execution reaches the part of the flow with the issue.
If it is desirable to have any issues reported as messages when trying to debug the flow, the user can cast the variable specified for Component to its correct type when using it (e.g. for UtcDateTime component it could be case as follows: (DateTime)($)Component).
6.3.2.4 - Get Time Period
Get the time period (Years, Months, Days, Hours, Minutes, Seconds and Milliseconds) between two date times.
($)TimePeriod is a variable that will be set to a TimePeriod value
Result
Getting the Time Period between 2021-01-01T00:00:00+00:00 and 2022-01-01T00:00:00+00:00 will result in the variable ($)TimePeriod being updated to the following:
Time Period can have positive and negative components where components are:
Years
Months
Days
Hours
Minutes
Seconds
Milliseconds
In this block, the Year and Month components are not used as they aren’t constant (i.e. Years can have different numbers of days depending upon whether it is a leap year or not, and months can have different numbers of days); instead Days will be used.
In this block, the Year and Month components are not used as they aren’t constant (i.e. Years can have different numbers of days depending upon whether it is a leap year or not, and months can have different numbers of days); instead Days will be used.
($)DateTime is a variable that will be set to a Boolean value
Result
Checking if 2022-01-01T00:00:00+00:00 is after 2021-01-01T00:00:00+00:00 will result in the variable ($)DateTimeIsAfter being updated to the following:
true
Date Time is before Date Time To Compare
This example will check if 2021-01-01T00:00:00+00:00 is after 2022-01-01T00:00:00+00:00.
($)DateTime is a variable that will be set to a Boolean value
Result
Checking if 2021-01-01T00:00:00+00:00 is after 2022-01-01T00:00:00+00:00 will result in the variable ($)DateTimeIsAfter being updated to the following:
false
Date Time is equal to Date Time To Compare
This example will check if 2022-01-01T00:00:00+00:00 is after 2022-01-01T00:00:00+00:00.
($)DateTime is a variable that will be set to a Boolean value
Result
Checking if 2022-01-01T00:00:00+00:00 is after 2022-01-01T00:00:00+00:00 will result in the variable ($)DateTimeIsAfter being updated to the following:
($)DateTime is a variable that will be set to a Boolean value
Result
Checking if 2021-01-01T00:00:00+00:00 is before 2022-01-01T00:00:00+00:00 will result in the variable ($)DateTimeIsBefore being updated to the following:
true
Date Time is after Date Time To Compare
This example will check if 2022-01-01T00:00:00+00:00 is before 2021-01-01T00:00:00+00:00.
($)DateTime is a variable that will be set to a Boolean value
Result
Checking if 2022-01-01T00:00:00+00:00 is before 2021-01-01T00:00:00+00:00 will result in the variable ($)DateTimeIsBefore being updated to the following:
false
Date Time is equal to Date Time To Compare
This example will check if 2022-01-01T00:00:00+00:00 is before 2022-01-01T00:00:00+00:00.
($)DateTime is a variable that will be set to a Boolean value
Result
Checking if 2022-01-01T00:00:00+00:00 is before 2022-01-01T00:00:00+00:00 will result in the variable ($)DateTimeIsBefore being updated to the following:
($)DateTime is a variable that will be set to a Boolean value
Result
Checking if 2021-06-01T00:00:00+00:00 is between 2021-01-01T00:00:00+00:00 and 2022-01-01T00:00:00+00:00 will result in the variable ($)DateTimeIsBetween being updated to the following:
true
Date Time is not between Start Date Time and End Date Time
This example will check if 2020-01-01T00:00:00+00:00 is between 2021-01-01T00:00:00+00:00 and 2022-01-01T00:00:00+00:00.
($)DateTime is a variable that will be set to a Boolean value
Result
Checking if 2020-01-01T00:00:00+00:00 is between 2021-01-01T00:00:00+00:00 and 2022-01-01T00:00:00+00:00 will result in the variable ($)DateTimeIsBetween being updated to the following:
If Date Time is between (and including) the Start Date Time and End Date Time, the specified variable will be set to true, otherwise it will be set to false.
The Start Date Time and End Date Time properties are both inclusive, which means if Date Time is equal to either of them, it will be considered between.
($)DateTime is a variable that will be set to a Boolean value
Result
Checking if 2022-01-01T00:00:00+00:00 is equal 2022-01-01T00:00:00+00:00 will result in the variable ($)DateTimeIsEqual being updated to the following:
true
Date Time is after Date Time To Compare
This example will check if 2022-01-01T00:00:00+00:00 is equal to 2021-01-01T00:00:00+00:00.
($)DateTime is a variable that will be set to a Boolean value
Result
Checking if 2022-01-01T00:00:00+00:00 is equal to 2021-01-01T00:00:00+00:00 will result in the variable ($)DateTimeIsEqual being updated to the following:
false
Date Time is before Date Time To Compare
This example will check if 2021-01-01T00:00:00+00:00 is equal to 2022-01-01T00:00:00+00:00.
($)DateTime is a variable that will be set to a Boolean value
Result
Checking if 2021-01-01T00:00:00+00:00 is equal to 2022-01-01T00:00:00+00:00 will result in the variable ($)DateTimeIsEqual being updated to the following:
Subtracting 1 year from 2022-01-01T00:00:00+00:00 will result in the variable ($)DateTime being updated. Its text representation will be in the ISO 8601 Standard, which can be seen below:
"2021-01-01T00:00:00+00:00"
Subtract a negative Time Period
This example will subtract -1 year from 2021-01-01T00:00:00+00:00.
Subtracting -1 year from 2021-01-01T00:00:00+00:00 will result in 1 year being added and the variable ($)DateTime being updated. Its text representation will be in the ISO 8601 Standard, which can be seen below:
Time Period can have positive and negative components where components are:
Years
Months
Days
Hours
Minutes
Seconds
Milliseconds
When subtracting a Time Period, the block will first subtract years, followed by months, days, hours, minutes, seconds and finally milliseconds.
When subtracting months, if the current day component is greater than the last day in the resultant month, it will update the day to the last day for that month (e.g. subtracting one month from 2021-02-28T23:59:59+00:00 will equate to 2021-01-31T23:59:59+00:00).
When subtracting a Time Period, the block will first subtract years, followed by months, days, hours, minutes, seconds and finally milliseconds.
Subtraction of Months
When subtracting months from the Date Time, if the current day component is greater than the last day in the resultant month, it will update the day to the last day for that month (e.g. subtracting one month from 2021-02-28T23:59:59+00:00 will equate to 2021-01-31T23:59:59+00:00).
Daylight Savings
This block copes with UTC time offsets but does not know anything about which time zone the Date Time represents; as a result it cannot take daylight savings into account as these are related to time zones rather than UTC time offsets.
6.3.3 - Decisions
Blocks related to making decisions and branching the path a flow execution takes.
6.3.3.1 - If Else
Perform if-else like conditional decision making.
6.3.3.1.1 - If Null Exit Bottom
Checks if a given value is null; if so the flow execution exits via the block’s bottom port, otherwise it exits via the right port.
Checks if a given Value is null; if so the flow execution exits via the block’s bottom port (green tick), otherwise it exits via the right port (red cross).
Checks if a given Value is null; if so the flow execution exits via the block’s right port (green tick), otherwise it exits via the bottom port (red cross).
Checks if a given Value evaluates to true; if so the flow execution exits via the block’s bottom port (green tick), otherwise it exits via the right port (red cross).
Examples
Value is true
This example will check if 1 + 1 == 2 evaluates to true or false.
Checks if a given value evaluates to true; if so the flow execution exits via the block’s right port, otherwise it exits via the bottom port.
If True Exit Right
(Cortex.Blocks.Decisions.If.IfTrueExitRightBlock)
Description
Checks if a given Value evaluates to true; if so the flow execution exits via the block’s right port (green tick), otherwise it exits via the bottom port (red cross).
Examples
Value is true
This example will check if 1 + 1 == 2 evaluates to true or false.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.2 - Contains Item(s)
Check if an item or multiple items are contained in a dictionary.
6.3.4.2.1 - Contains Item With Key
Checks if a Dictionary contains at least one item with the specified key.
Checks if Dictionary contains at least one item with the specified Key.
Examples
Dictionary contains item with Key
This example will check whether {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains at least one item with the key "Key1".
($)ContainsItem is a variable that will be set to a Boolean value
Result
{"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains one item with the key Key1. Therefore, the variable ($)ContainsItem will be updated to the following:
true
Dictionary does not contain item with Key
This example will check whether {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains at least one item with the key "Key10".
($)ContainsItem is a variable that will be set to a Boolean value
Result
{"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} does not contain any items with the key "Key10". Therefore, the variable ($)ContainsItem will be updated to the following:
false
Properties
Dictionary
The Dictionary to check whether it contains at least one item with the specified Key.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.2.2 - Contains Item With Key And Value
Checks if a Dictionary contains at least one item with the specified key and matching the specified value.
Checks if Dictionary contains at least one item with the specified Key and matching the specified Value.
Examples
Dictionary contains item with Key and Value
This example will check whether {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains at least one item with the key "Key1" and value 1.
($)ContainsItem is a variable that will be set to a Boolean value
Result
{"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains one item with the key Key1 and value 1. Therefore, the variable ($)ContainsItem will be updated to the following:
true
Dictionary does not contain item with Key and Value
This example will check whether {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains at least one item with the key "Key1" and value 10.
($)ContainsItem is a variable that will be set to a Boolean value
Result
{"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains one item with the key "Key1", but its value is not 10. Therefore, the variable ($)ContainsItem will be updated to the following:
false
Properties
Dictionary
The Dictionary to check whether it contains at least one item with the specified Key and matching Value.
If Dictionary contains at least one item with the specified Key and matching Value, the specified variable will be set to true, otherwise it will be set to false.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.2.3 - Contains Item With Value
Checks if a Dictionary contains at least one item matching the specified value.
($)ContainsItem is a variable that will be set to a Boolean value
Result
{"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains two items with the value 1. Therefore, the variable ($)ContainsItem will be updated to the following:
true
Dictionary does not contain item with Value
This example will check whether {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains the value 10.
($)ContainsItem is a variable that will be set to a Boolean value
Result
{"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} does not contain any items with the value 10. Therefore, the variable ($)ContainsItem will be updated to the following:
false
Properties
Dictionary
The Dictionary to check whether it contains at least one item matching the specified Value.
Items are considered matching if they have the specified Value.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.2.4 - Contains Items With Keys
Checks if a Dictionary contains at least one item with each of the specified keys.
Checks if Dictionary contains at least one item with each of the specified Keys.
Examples
Dictionary contains items with Keys
This example will check whether {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains at least one item with each of the keys in ["Key1", "Key2", "Key3"].
($)ContainsItems is a variable that will be set to a Boolean value
Result
{"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains at least one item matching each of the values in ["Key1", "Key2", "Key3"]; it contains one item with the key "Key1", one item with the key "Key2" and one item with the key "Key3". Therefore, the variable ($)ContainsItems will be updated to the following:
true
Dictionary does not contain items with Keys
This example will check whether {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains at least one item with each of the keys in ["Key1", "Key2", "Key3", "Key10"].
($)ContainsItems is a variable that will be set to a Boolean value
Result
{"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} does not contain at least one item matching each of the values in ["Key1", "Key2", "Key3"]; it contains one item with the key "Key1", one item with the key "Key2" and one item with the key "Key3", but no items with the key "Key10". Therefore, the variable ($)ContainsItems will be updated to the following:
false
Properties
Dictionary
The Dictionary to check whether it contains at least one item with each of the specified Keys.
If Dictionary contains at least one item with each of the specified Keys, the specified variable will be set to true, otherwise it will be set to false.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.2.5 - Contains Items With Values
Checks if a Dictionary contains at least one item matching each of the specified values.
Checks if Dictionary contains at least one item matching each of the specified Values.
Examples
Dictionary contains items with Values
This example will check whether {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains at least one item matching each of the values in [1, 2, 3].
($)ContainsItems is a variable that will be set to a Boolean value
Result
{"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains at least one item matching each of the values in [1, 2, 3]; it contains two items with the value 1, two items with the value 2 and two items with the value 3. Therefore, the variable ($)ContainsItems will be updated to the following:
true
Dictionary does not contain items with Values
This example will check whether {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} contains at least one item matching each of the values in [1, 2, 3, 10].
($)ContainsItems is a variable that will be set to a Boolean value
Result
{"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} does not contain at least one item matching each of the values in [1, 2, 3, 10]; it contains two items with the value 1, two items with the value 2 and two items with the value 3, but no items with the value 10. Therefore, the variable ($)ContainsItems will be updated to the following:
false
Properties
Dictionary
The Dictionary to check whether it contains at least one item matching each of the specified Values.
Items are considered matching if they have a value matching one of the specified Values.
If Dictionary contains at least one item matching each of the specified Values, the specified variable will be set to true, otherwise it will be set to false.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
($)Count is a variable that will be set to an Int32 value
Result
Getting the count of all items in {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} results in the variable ($)Count being updated to the following:
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.3.2 - Get Count Of Items With Value
Gets the count of items in a Dictionary with the specified value.
($)Count is a variable that will be set to an Int32 value
Result
Getting the count of items in {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} with the value 1 results in the variable ($)Count being updated to the following:
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.3.3 - Get Counts Of Items With Values
Gets the counts of items in a Dictionary matching each of the specified values.
Get Counts of items in a Dictionary matching each of the Values
This example will get the counts of items in {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} matching each of the values [1, 2, 3].
($)Counts is a variable that will be set to an IList<Int32> value
Result
Getting the counts of items in {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} matching each of the values [1, 2, 3] results in the variable ($)Counts being updated to the following:
[2,2,2]
The counts of items matching each value are added to ($)Counts at the same index the value is in ($)Values. In this example, there are two items matching the first value 1, two items matching the second value 2 and two items matching the third value 3, resulting in ($)Counts being set to [2, 2, 2].
For each value in Values, Counts will have a corresponding item whose value is the count of items in Dictionary matching the value.
I.e. The count of items matching the first value in Values will be saved as the first item in Counts; the count of items matching the second value in Values will be saved as the second item in Counts etc.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
($)Items is a variable that will be set to an IList<Int32>
Result
Getting all items from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} results in the variable ($)Items being updated to the following:
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.4.2 - Get Item With Key
Gets the specified occurrence of an item with the given key from a Dictionary.
Get the first Occurrence of an Item with a Key from a Dictionary
This example will attempt to get the first occurrence of an item with the key "Key1" from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1}.
($)Item is a variable that will be set to the type of the item (i.e. Int32)
Result
An Occurrence of 1 means get the first occurrence; 2 means second etc.
Attempting to get the first occurrence of an item with the key "Key1" from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} results in the variable ($)Item being updated to the following:
1
Get the last Occurrence of an Item with a Key from a Dictionary
Typically keys are simple data types such as String, Int32, Boolean, and for these a dictionary cannot the same key value more than once. This is due to how the data type’s object equality is implemented (two items are considered equal if they have the same value rather than being the same object reference).
However, other data types such as IList<Int32> can also be used as keys. For these data types, object equality only considers two items equal if they are the same reference; it does not care about whether they have the same value. Therefore, it is possible to have the same key value more than once, and as a result you should be able to get an occurrence of item with that key.
This example will illustrate this, by attempting to get the last occurrence of an item with the key [1] from {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 10}.
($)Item is a variable that will be set to the type of the item (i.e. Int32)
Result
An Occurrence of -1 means get the last occurrence; -2 means second last etc.
Attempting to get the last occurrence of an item with the key [1] from {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 10} results in the variable ($)Item being updated to the following:
Items are considered matching if they have the specified Key.
Unlike lists, dictionaries do not have a defined order. This means the nth occurrence is determined by the underlying Microsoft .Net implementation; this is not published and could change if the algorithm were to change.
For information and examples of how it is determined whether a key is already present, please see Object Equality.
Occurrences
Unlike lists, dictionaries do not have a defined order. This means the nth occurrence is determined by the underlying Microsoft .Net implementation; this is not published and could change if the algorithm were to change.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.4.3 - Get Items With Key
Gets all items with the given key from a Dictionary.
Typically keys are simple data types such as String, Int32, Boolean, and for these a dictionary cannot the same key value more than once. This is due to how the data type’s object equality is implemented (two items are considered equal if they have the same value rather than being the same object reference).
However, other data types such as IList<Int32> can also be used as keys. For these data types, object equality only considers two items equal if they are the same reference; it does not care about whether they have the same value. Therefore, it is possible to have the same key value more than once, and as a result you should be able to get all items with that key.
This example will illustrate this, by attempting to get all items with the key [1] from {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 10}.
($)Items is a variable that will be set to an IList<Int32>
Result
Attempting to get all items with the key [1] from {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 10} results in the variable ($)Items being updated to the following:
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
($)Keys is a variable that will be set to an IList<String>
Result
Getting all keys from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} results in the variable ($)Keys being updated to the following:
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.6 - Remove Item(s)
Remove an item or multiple items from a dictionary.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.6.2 - Remove Item With Key
Removes the specified occurrence of an item with the given key from a Dictionary.
Attempting to remove the first occurrence of an item with the key "Key1" from {} results in no operation, as there is nothing to remove. Therefore, the variable ($)Dictionary remains:
{}
Remove the first Occurrence of an item with a Key from a Dictionary
This example will attempt to remove the first occurrence of an item with the key "Key1" from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1}.
An Occurrence of 1 means remove the first occurrence; 2 means second etc.
Attempting to remove the first occurrence of an item with the key "Key1" from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} results in the variable ($)Dictionary being updated to the following:
{"Key2":2,"Key3":3,"Key4":3,"Key5":2,"Key6":1}
Remove the last Occurrence of an item with a Key from a Dictionary
Typically keys are simple data types such as String, Int32, Boolean, and for these a dictionary cannot the same key value more than once. This is due to how the data type’s object equality is implemented (two items are considered equal if they have the same value rather than being the same object reference).
However, other data types such as IList<Int32> can also be used as keys. For these data types, object equality only considers two items equal if they are the same reference; it does not care about whether they have the same value. Therefore, it is possible to have the same key value more than once, and as a result you should be able to remove any occurrence of item with that key.
This example will illustrate this, by attempting to remove the last occurrence of an item with the key [1] from {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 1}.
An Occurrence of -1 means remove the last occurrence; -2 means second last etc.
Attempting to remove the last occurrence of an item with the key [1] from {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 1} results in the variable ($)Dictionary being updated to the following:
Items are considered matching if they have the specified Key.
Unlike lists, dictionaries do not have a defined order. This means the nth occurrence is determined by the underlying Microsoft .Net implementation; this is not published and could change if the algorithm were to change.
For information and examples of how it is determined whether a key is already present, please see Object Equality.
Occurrences
Unlike lists, dictionaries do not have a defined order. This means the nth occurrence is determined by the underlying Microsoft .Net implementation; this is not published and could change if the algorithm were to change.
If Dictionary is empty (i.e. {}) there is nothing to remove, so no operation is performed.
No items with given Key, or Occurrence is not present
If Dictionary does not contain items with the given Key or the specified Occurrence is not present, there is nothing to remove, so no operation is performed.
Defining dictionaries using literal syntax
For information about how to define dictionaries using literal syntax, see Dictionary Literals.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.6.3 - Remove Item With Value
Removes the specified occurrence of an item matching a value from a Dictionary.
Attempting to remove the first occurrence of an item matching the value 1 from {} results in no operation, as there is nothing to remove. Therefore, the variable ($)Dictionary remains:
{}
Remove the first Occurrence of an item matching a Value from a Dictionary
This example will attempt to remove the first occurrence of an item matching the value 1 from {"Key1" : 1, "Key2" : 1}.
An Occurrence of 1 means remove the first occurrence; 2 means second etc.
Attempting to remove the first occurrence of an item matching the value 1 from {"Key1" : 1, "Key2" : 1} results in the variable ($)Dictionary being updated to the following:
{"Key2":1}
Remove the last Occurrence of an item matching a Value from a Dictionary
This example will attempt to remove the last occurrence of an item matching the value 1 from {"Key1" : 1, "Key2" : 1}.
An Occurrence of -1, means remove the last occurrence; -2 means second last etc.
Attempting to remove the last occurrence of an item matching the value 1 from {"Key1" : 1, "Key2" : 1} results in the variable ($)Dictionary being updated to the following:
Items are considered matching if they have the specified Value.
Unlike lists, dictionaries do not have a defined order. This means the nth occurrence is determined by the underlying Microsoft .Net implementation; this is not published and could change if the algorithm were to change.
For information and examples of how it is determined whether an item matches a specified value, please see Object Equality.
Occurrences
Unlike lists, dictionaries do not have a defined order. This means the nth occurrence is determined by the underlying Microsoft .Net implementation; this is not published and could change if the algorithm were to change.
If Dictionary is empty (i.e. {}) there is nothing to remove, so no operation is performed.
No items matching Value, or Occurrence is not present
If Dictionary does not contain items matching the specified Value or the specified Occurrence is not present, there is nothing to remove, so no operation is performed.
Defining dictionaries using literal syntax
For information about how to define dictionaries using literal syntax, see Dictionary Literals.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.6.4 - Remove Items With Key
Removes all items with the given key from a Dictionary.
Attempting to remove all items with the key "Key1" from {} results in no operation, as there is nothing to remove. Therefore, the variable ($)Dictionary remains:
{}
Remove all items with a Key from a Dictionary
Typically keys are simple data types such as String, Int32, Boolean, and for these a dictionary cannot the same key value more than once. This is due to how the data type’s object equality is implemented (two items are considered equal if they have the same value rather than being the same object reference).
However, other data types such as IList<Int32> can also be used as keys. For these data types, object equality only considers two items equal if they are the same reference; it does not care about whether they have the same value. Therefore, it is possible to have the same key value more than once, and as a result you should be able to remove all items with that key.
This example will illustrate this, by attempting to remove all items with the key [1] from {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 1}.
Attempting to remove all items with the key [1] from {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 1} results in the variable ($)Dictionary being updated to the following:
{[2]:2,[3]:3,[3]:3,[2]:2}
Properties
Dictionary
The Dictionary to remove all items with the given Key from.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.6.5 - Remove Items With Keys
Removes all items with any of the given keys from a Dictionary.
Attempting to remove all items with any of the given keys in ["Key1", "Key2"] from {} results in no operation, as there is nothing to remove. Therefore, the variable ($)Dictionary remains:
{}
Remove all items with any of the given Keys from a Dictionary
This example will attempt to remove all items with any of the given keys in ["Key1", "Key2"] from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1}.
Attempting to remove all items with any of the given keys in ["Key1", "Key2"] from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} results in the variable ($)Dictionary being updated to the following:
{"Key3":3,"Key4":3,"Key5":2,"Key6":1}
Properties
Dictionary
The Dictionary to remove all items with any of the given Keys from.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.6.6 - Remove Items With Value
Removes all items matching a value from a Dictionary.
Attempting to remove all items matching the value 1 from {} results in no operation, as there is nothing to remove. Therefore, the variable ($)Dictionary remains:
{}
Remove all items matching a Value from a Dictionary
This example will attempt to remove all items matching the value 1 from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1}.
Attempting to remove all items matching the value 1 from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} results in the variable ($)Dictionary being updated to the following:
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.6.7 - Remove Items With Values
Removes all items matching one of the specified values from a Dictionary.
Attempting to remove all items matching one of the values [1, 2] from {} results in no operation, as there is nothing to remove. Therefore, the variable ($)Dictionary remains:
{}
Remove all items matching one of the specified Values from a Dictionary
This example will attempt to remove all items matching one of the values [1, 2] from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1}.
Attempting to remove all items matching one of the values [1, 2] from {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} results in the variable ($)Dictionary being updated to the following:
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.7 - Set Item(s)
Set an item or multiple items in a dictionary to a new value.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.7.2 - Set Item With Key
Sets the specified occurrence of an item with the given key in a Dictionary to a new value.
An Occurrence of 1 means set the first occurrence; 2 means second etc.
Attempting to set the first occurrence of an item with the key "Key1" in {"Key1" : 1, "Key2" : 2} to 10 results in the variable ($)Dictionary being updated to the following:
{"Key1":10,"Key2":1}
Set the last Occurrence of an item with a Key in a Dictionary to a New Value
Typically keys are simple data types such as String, Int32, Boolean, and for these a dictionary cannot the same key value more than once. This is due to how the data type’s object equality is implemented (two items are considered equal if they have the same value rather than being the same object reference).
However, other data types such as IList<Int32> can also be used as keys. For these data types, object equality only considers two items equal if they are the same reference; it does not care about whether they have the same value. Therefore, it is possible to have the same key value more than once, and as a result you should be able to set an occurrence of item with that key.
This example will illustrate this, by attempting to set the last occurrence of an item with the key [1] in {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 1} to 10.
An Occurrence of -1, means set the last occurrence; -2 means second last etc.
Attempting to set the last occurrence of an item with the key [1] in {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 1} to 10 results in the variable ($)Dictionary being updated to the following:
Items are considered matching if they have the specified Key.
Unlike lists, dictionaries do not have a defined order. This means the nth occurrence is determined by the underlying Microsoft .Net implementation; this is not published and could change if the algorithm were to change.
For information and examples of how it is determined whether a key is already present, please see Object Equality.
Occurrences
Unlike lists, dictionaries do not have a defined order. This means the nth occurrence is determined by the underlying Microsoft .Net implementation; this is not published and could change if the algorithm were to change.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.7.3 - Set Item With Value
Sets the specified occurrence of an item matching a value in a Dictionary to a new value.
An Occurrence of 1 means set the first occurrence; 2 means second etc.
Attempting to set the first occurrence of an item matching the value 1 in {"Key1" : 1, "Key2" : 1} to 10 results in the variable ($)Dictionary being updated to the following:
{"Key1":10,"Key2":1}
Set the last Occurrence of an item matching a Value in a Dictionary to a New Value
This example will attempt to set the last occurrence of an item matching the value 1 in {"Key1" : 1, "Key2" : 1} to 10.
An Occurrence of -1, means set the last occurrence; -2 means second last etc.
Attempting to set the last occurrence of an item matching the value 1 in {"Key1" : 1, "Key2" : 1} to 10 results in the variable ($)Dictionary being updated to the following:
Items are considered matching if they have the specified Value.
Unlike lists, dictionaries do not have a defined order. This means the nth occurrence is determined by the underlying Microsoft .Net implementation; this is not published and could change if the algorithm were to change.
For information and examples of how it is determined whether an item matches a specified value, please see Object Equality.
Occurrences
Unlike lists, dictionaries do not have a defined order. This means the nth occurrence is determined by the underlying Microsoft .Net implementation; this is not published and could change if the algorithm were to change.
If Dictionary is empty (i.e. {}) there is nothing to set, so no operation is performed.
No items matching Value, or Occurrence is not present
If Dictionary does not contain items matching the specified Value or the specified Occurrence is not present, there is nothing to set, so no operation is performed.
Defining dictionaries using literal syntax
For information about how to define dictionaries using literal syntax, see Dictionary Literals.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.7.4 - Set Items With Key
Sets all items with the given key in a Dictionary to a new value.
Sets all items with a Key in a Dictionary to a New Value
Typically keys are simple data types such as String, Int32, Boolean, and for these a dictionary cannot the same key value more than once. This is due to how the data type’s object equality is implemented (two items are considered equal if they have the same value rather than being the same object reference).
However, other data types such as IList<Int32> can also be used as keys. For these data types, object equality only considers two items equal if they are the same reference; it does not care about whether they have the same value. Therefore, it is possible to have the same key value more than once, and as a result you should be able to set all items with that key.
This example will illustrate this, by attempting to set all items with the key [1] in {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 1} to 10.
Attempting to set all items with the key [1] in {[1] : 1, [2] : 2, [3] : 3, [3] : 3, [2] : 2, [1] : 1} to 10 results in the variable ($)Dictionary being updated to the following:
{[1]:10,[2]:2,[3]:3,[3]:3,[2]:2,[1]:10}
Properties
Dictionary
The Dictionary to set all items with the given Key in.
Items are considered matching if they have the specified Key.
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.7.5 - Set Items With Keys
Sets all items with any of the given keys in a Dictionary to new values.
Set all items with any of the given Keys in a Dictionary to New Values
This example will attempt to set all items with any of the keys ["Key1", "Key2"] in {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} to [10, 20] respectively.
Attempting to set all items with any of the keys ["Key1", "Key2"] in {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} to [10, 20] respectively, results in the variable ($)Dictionary being updated to the following:
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.7.6 - Set Items With Value
Sets all items matching a value in a Dictionary to a new value.
Attempting to set all items matching the value 1 in {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} to 10 results in the variable ($)Dictionary being updated to the following:
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
6.3.4.7.7 - Set Items With Values
Sets all items matching one of the specified values in a Dictionary to new values.
Set all items matching one of the specified Values in a Dictionary to New Values
This example will attempt to set all items matching one of the values [1, 2] in {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} to [10, 20] respectively.
Attempting to set all items matching one of the values [1, 2] in {"Key1" : 1, "Key2" : 2, "Key3" : 3, "Key4" : 3, "Key5" : 2, "Key6" : 1} to [10, 20] respectively, results in the variable ($)Dictionary being updated to the following:
Dictionaries containing items with same data types vs different data types
For information about the different types of dictionaries, including those that can contain only the same type of item, and those that can contain different types of item, see Dictionaries.
Close Session can be specified to choose whether the connection to the SMTP server is closed or is kept open for use on subsequent Send Email Using SMTP Server blocks.
Examples
Sending an email to a single recipient
This example will send an email from sender@gmail.com to recipient@outlook.com. The example uses the SMTP server hosted at smtp.gmail.com on Port465 which requires UseSsl to be to set to true within the Basic Email Session Details.
For more information about when UseSsl should be set to true or false, see Setting UseSsl.
($)BasicEmailSessionDetails with value {"ServerDetails": {"Host": "smtp.gmail.com", "Port": 465, "UseSsl": true}, "Credentials": {"Domain": null, "Username": "sender@gmail.com", "Password": "encryptedPassword"}}
In this example ($)BasicEmailSessionDetails has been set up using the following Expression:
new BasicEmailSessionDetails(serverDetails: new ServerDetails("smtp.gmail.com", 465, true), credentials: new UserCredentials("sender@gmail.com", "encryptedPassword"))
An email with Normal priority is sent from sender@gmail.com to recipient@outlook.com with a subject of "Example email subject" and a Text body of "Example email body", and then the session is closed.
Sending an email to multiple recipients
This example will send an email from sender@gmail.com to recipient1@outlook.com, recipient2@outlook.com and recipient3@outlook.com. The example uses the SMTP server hosted at smtp.gmail.com on Port465 which requires UseSsl to be set to true within the Basic Email Session Details.
For more information about when UseSsl should be set to true or false, see Setting UseSsl.
($)BasicEmailSessionDetails with value {"ServerDetails": {"Host": "smtp.gmail.com", "Port": 465, "UseSsl": true}, "Credentials": {"Domain": null, "Username": "sender@gmail.com", "Password": "encryptedPassword"}}
In this example ($)BasicEmailSessionDetails has been set up using the following Expression:
new BasicEmailSessionDetails(serverDetails: new ServerDetails("smtp.gmail.com", 465, true), credentials: new UserCredentials("sender@gmail.com", "encryptedPassword"))
An email with Normal priority is sent from sender@gmail.com to recipient1@outlook.com, recipient2@outlook.com and recipient3@outlook.com with a subject of "Example email subject" and a Text body of "Example email body", and then the session is closed.
Sending an email with a CC or BCC recipient
This example will send an email from sender@gmail.com to recipient@outlook.com with cc@outlook.com and bcc@outlook.com as the CC and BCC recipients for the email respectively. The example uses the SMTP server hosted at smtp.gmail.com on Port465 which requires UseSsl to be set to true within the Basic Email Session Details.
For more information about when UseSsl should be set to true or false, see Setting UseSsl.
In this example ($)EmailMessage has been set up using the following Expression:
new EmailMessage(to: new List<EmailAddress>(){ new EmailAddress("recipient@outlook.com") }, from: new EmailAddress("sender@gmail.com"), cc: new List<EmailAddress>(){ new EmailAddress("cc@outlook.com") }, bcc: new List<EmailAddress>(){ new EmailAddress("bcc@outlook.com") }, priority: null, subject: "Example email subject", bodyFormat: null, body: "Example email body", attachments: null)
($)EmailMessage is a variable of type EmailMessage
($)BasicEmailSessionDetails with value {"ServerDetails": {"Host": "smtp.gmail.com", "Port": 465, "UseSsl": true}, "Credentials": {"Domain": null, "Username": "sender@gmail.com", "Password": "encryptedPassword"}}
In this example ($)BasicEmailSessionDetails has been set up using the following Expression:
new BasicEmailSessionDetails(serverDetails: new ServerDetails("smtp.gmail.com", 465, true), credentials: new UserCredentials("sender@gmail.com", "encryptedPassword"))
An email with Normal priority is sent from sender@gmail.com to recipient@outlook.com with a subject of "Example email subject" and a Text body of "Example email body". Both cc@outlook.com and bcc@outlook.com will also recieve copies of the email as they are listed as CC and BCC recipients, and then the session is closed.
Sending an email with multiple CC or BCC recipients
This example will send an email from sender@gmail.com to recipient@outlook.com with cc1@outlook.com and cc2@outlook.com as the CC recipients and bcc1@outlook.com and bcc2@outlook.com as the BCC recipients for the email. The example uses the SMTP server hosted at smtp.gmail.com on Port465 which requires UseSsl to be set to true within the Basic Email Session Details.
For more information about when UseSsl should be set to true or false, see Setting UseSsl.
In this example ($)EmailMessage has been set up using the following Expression:
new EmailMessage(to: new List<EmailAddress>(){ new EmailAddress("recipient@outlook.com") }, from: new EmailAddress("sender@gmail.com"), cc: new List<EmailAddress>(){ new EmailAddress("cc1@outlook.com"), new EmailAddress("cc2@outlook.com") }, bcc: new List<EmailAddress>(){ new EmailAddress("bcc1@outlook.com"), new EmailAddress("bcc2@outlook.com") }, priority: null, subject: "Example email subject", bodyFormat: null, body: "Example email body", attachments: null)
($)EmailMessage is a variable of type EmailMessage
($)BasicEmailSessionDetails with value {"ServerDetails": {"Host": "smtp.gmail.com", "Port": 465, "UseSsl": true}, "Credentials": {"Domain": null, "Username": "sender@gmail.com", "Password": "encryptedPassword"}}
In this example ($)BasicEmailSessionDetails has been set up using the following Expression:
new BasicEmailSessionDetails(serverDetails: new ServerDetails("smtp.gmail.com", 465, true), credentials: new UserCredentials("sender@gmail.com", "encryptedPassword"))
An email with Normal priority is sent from sender@gmail.com to recipient@outlook.com with a subject of "Example email subject" and a Text body of "Example email body". Both cc1@outlook.com and cc2@outlook.com will also recieve copies of the email as they are listed as CC recipients, and both bcc1@outlook.com and bcc2@outlook.com will recieve copies of the email as they are listed as BCC recipients. Finally, the session is closed.
Sending an email with a different priority
This example will send an email with Urgent priority from sender@gmail.com to recipient@outlook.com. The example uses the SMTP server hosted at smtp.gmail.com on Port465 which requires UseSsl to be set to true within the Basic Email Session Details.
($)BasicEmailSessionDetails with value {"ServerDetails": {"Host": "smtp.gmail.com", "Port": 465, "UseSsl": true}, "Credentials": {"Domain": null, "Username": "sender@gmail.com", "Password": "encryptedPassword"}}
In this example ($)BasicEmailSessionDetails has been set up using the following Expression:
new BasicEmailSessionDetails(serverDetails: new ServerDetails("smtp.gmail.com", 465, true), credentials: new UserCredentials("sender@gmail.com", "encryptedPassword"))
An email with Urgent priority is sent from sender@gmail.com to recipient@outlook.com with a subject of "Example email subject" and a Text body of "Example email body", and then the session is closed.
Sending an email with an HTML body
This example will send an email with an HTML body from sender@gmail.com to recipient@outlook.com. The example uses the SMTP server hosted at smtp.gmail.com on Port465 which requires UseSsl to be set to true within the Basic Email Session Details.
($)BasicEmailSessionDetails with value {"ServerDetails": {"Host": "smtp.gmail.com", "Port": 465, "UseSsl": true}, "Credentials": {"Domain": null, "Username": "sender@gmail.com", "Password": "encryptedPassword"}}
In this example ($)BasicEmailSessionDetails has been set up using the following Expression:
new BasicEmailSessionDetails(serverDetails: new ServerDetails("smtp.gmail.com", 465, true), credentials: new UserCredentials("sender@gmail.com", "encryptedPassword"))
An email with Normal priority is sent from sender@gmail.com to recipient@outlook.com with a subject of "Example email subject" and an HTML body of "<h1>Example email body</h1>", and then the session is closed.
Sending an email with a single attachment
This example will send an email with a single attachment, attachment.txt, from sender@gmail.com to recipient@outlook.com. The attachment is located at C:\attachment.txt on the server executing the flow. The example uses the SMTP server hosted at smtp.gmail.com on Port465 which requires UseSsl to be set to true within the Basic Email Session Details.
($)BasicEmailSessionDetails with value {"ServerDetails": {"Host": "smtp.gmail.com", "Port": 465, "UseSsl": true}, "Credentials": {"Domain": null, "Username": "sender@gmail.com", "Password": "encryptedPassword"}}
In this example ($)BasicEmailSessionDetails has been set up using the following Expression:
new BasicEmailSessionDetails(serverDetails: new ServerDetails("smtp.gmail.com", 465, true), credentials: new UserCredentials("sender@gmail.com", "encryptedPassword"))
An email with Normal priority containing a text file attachment, attachment.txt, is sent from sender@gmail.com to recipient@outlook.com with a subject of "Example email subject" and a Text body of "Example email body", and then the session is closed.
Sending an email with multiple attachments
This example will send an email with mutiple attachments, attachment1.txt and attachment2.txt from sender@gmail.com to recipient@outlook.com. The attachments are located at the paths C:\attachment1.txt and C:\attachment2.txt on the server executing the flow. The example uses the SMTP server hosted at smtp.gmail.com on Port465 which requires UseSsl to be set to true within the Basic Email Session Details.
($)BasicEmailSessionDetails with value {"ServerDetails": {"Host": "smtp.gmail.com", "Port": 465, "UseSsl": true}, "Credentials": {"Domain": null, "Username": "sender@gmail.com", "Password": "encryptedPassword"}}
In this example ($)BasicEmailSessionDetails has been set up using the following Expression:
new BasicEmailSessionDetails(serverDetails: new ServerDetails("smtp.gmail.com", 465, true), credentials: new UserCredentials("sender@gmail.com", "encryptedPassword"))
An email with Normal priority containing two text file attachments, attachment1.txt and attachment2.txt, is sent from sender@gmail.com to recipient@outlook.com with a subject of "Example email subject" and a Text body of "Example email body", and then the session is closed.
Sending an email with UseSsl set to false
This example will send an email from sender@outlook.com to recipient@outlook.com. The example uses the SMTP server hosted at smtp-mail.outlook.com on Port587 which requires UseSsl to be set to false within the Basic Email Session Details.
For more information on when UseSsl should be set to true or false, see Setting UseSsl.
($)BasicEmailSessionDetails with value {"ServerDetails": {"Host": "smtp-mail.outlook.com", "Port": 587, "UseSsl": false}, "Credentials": {"Domain": null, "Username": "sender@outlook.com", "Password": "encryptedPassword"}}
In this example ($)BasicEmailSessionDetails has been set up using the following Expression:
new BasicEmailSessionDetails(serverDetails: new ServerDetails("smtp-mail.outlook.com", 587, false), credentials: new UserCredentials("sender@outlook.com", "encryptedPassword"))
An email with Normal priority is sent from sender@outlook.com to recipient@outlook.com with a subject of "Example email subject" and a Text body of "Example email body", and then the session is closed.
Properties
Email Message
The Email Message to send via the SMTP server specified in the Basic Email Session Details. This property contains all of the information in relation to the email to be sent, these are:
The Basic Email Session Details object that includes all of the information required to open and maintain a session with an SMTP server, including:
ServerDetails - must be provided in order to connect to an SMTP server. This object contains the properties Host, Port and UseSsl. For more information on:
Credentials - must be provided in order to connect to an SMTP server. This object contains the properties Username and Password to be used for authentication. For more information, see Setting Credentials.
If the Close Session property is set to false, then the session will be kept open and can be used in subsequent Send Email Using SMTP Server blocks which improves performance, see Opening Sessions for more information.
Close Session can be specified to choose whether the session is closed or is kept open for use on subsequent Send Email Using SMTP Server blocks, this defaults to false if left blank, please see Closing Sessions for more information.
Thrown when a file path provided in the Attachments within the Email Message is empty (i.e. ""), contains only whitespace (i.e. " ") or contains the NUL character (i.e. \0).
Thrown when a connection cannot be established; this typically occurs when UseSsl within Basic Email Session Details is set to false with a Port which requires it to be set to true. For more information, see SSL Required.
Thrown when a connection cannot be established; this typically occurs when UseSsl within Basic Email Session Details is set to true with a Port which requires it to be set to false. For more information, see SSL Not Supported.
Thrown when the TLS/SSL certificate has expired on the Host or is untrusted or invalid. For more information, see SSL Not Supported. Note that this exception has the same category and error code as the above row, this is a known limitation, see EmailSessionErrorCode Limitations.
Thrown when a locally installed anti-virus software replaces the TLS/SSL certificate in order to scan web traffic. For more information, see SSL Not Supported. Note that this exception has the same category and error code as the above row, this is a known limitation, see EmailSessionErrorCode Limitations.
Thrown when the CRL (Certificate Revocation List) server for the TLS/SSL certificate is down. For more information, see SSL Not Supported. Note that this exception has the same category and error code as the above row, this is a known limitation, see EmailSessionErrorCode Limitations.
Thrown when the combined size of all of the attachments in the list of Attachments within the Email Message is greater than the limit specified by the email service provider; for Outlook this is 20 MB and for Gmail this is 25 MB).
Thrown when a file path within the Attachments property within Email Message points to a folder.
Remarks
How does Priority affect sending an email?
An email sent with Urgent or NonUrgent priority will have its priority displayed differently depending on the email client. For example, Outlook displays an email that has an Urgent priority with a red exclamation mark like so:
For more information on how the priority of an email will be displayed, see the help provided by the respective email client.
How does BodyFormat affect sending an email?
An email sent with an HTML body will have its body displayed as an HTML page instead of as plain text. How the email looks in the email client may differ depending on the email client in use. For example, if the Email Message has its BodyFormat set to HTML and the Body has a value of:
For more information on how the body of an email will be displayed, see the help provided by the respective email client.
Attachments
Attachments can be sent in an email by providing a list of file paths in the Attachments property of the Email Message. For more information concerning attaching files to an email, see the sections below.
where each file path must be accessible from the server executing the flow.
For more information about each of these supported file path formats, please see File & Folder Paths.
File paths need escaping
Each file path in the Attachments within the Email Message requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Attachments\\attachment.txt"), or
Prepending an @ character before the start of the File Path (e.g. @"C:\Attachments\attachment.txt")
If a file path in the Attachments within the Email Message is invalid (i.e. contains any of the following characters: “, *, ?, |, <, >, :, , /), an IOException will be thrown.
If a file path in the Attachments within the Email Message contains leading spaces they are not removed and an IOException will be thrown; however, trailing spaces are removed.
File path contains only whitespace or the NUL character
The combined size of all the Attachments within the Email Message must be less than the limit specified by the email service provider. If the combined size of all of the attachments is greater than the limit, an SmtpCommandException will be thrown.
For Outlook this is 20 MB and for Gmail this is 25 MB, for more information on the size limits for other email service providers, see the help provided by the respective email service provider.
Fully Qualified Domain Name (e.g. "smtp.gmail.com")
Machine name (e.g. "mail-server1")
IP address (e.g. "127.0.0.1")
Localhost (e.g. "localhost")
Setting UseSsl
The ServerDetails within the Basic Email Session Details specifies which SMTP server to connect to. The value of the UseSsl property inside this object depends on the Host and Port being connected to. There are two types of SSL/TLS connections that can occur:
SSL/TLS is used as soon as a connection is established
SSL/TLS is used via the STARTTLS command if it is available
The above two points correspond to the UseSsl property being set to true and false respectively. As such, generally the following rules can be followed to determine whether UseSsl should be set to true or false:
If the Port being connected to is 465 then UseSsl should be set to true
If the Port being connected to is 25 or 567 then UseSsl should be set to false
Note that the UserCredentials object also contains a Domain property which is ignored by this block.
Opening Sessions
The Send Email Using SMTP Server block automatically handles creating and opening sessions for the specified Basic Email Session Details using the following rules:
If a session does not exist, a new session will be created, opened and used when the block runs.
If a session already exists but is closed, the session will be opened and used when the block runs.
If a session already exists and is open, the session will be used when the block runs.
Basic Email Session Details will keep the session open across multiple Send Email Using SMTP Server blocks as long as Close Session is set to false. Keeping the session open helps increase the performance of the block due to the subsequent blocks not having to spend resources creating and opening sessions for each execution.
Note that for all SSL connections, the protocol to be used will be negotiated with the server depending on which protocols are available. Similarly, the SASL mechanism to be used will be negotiated with the mail server based on the available mechanisms.
For information on how to explicitly close a session, please see Closing Sessions.
Closing Sessions
Sessions can be explicitly closed by setting Close Session to true. This causes the session to be closed after the Email Message has been sent.
If Close Session is set to false the session will be closed when the Variable that Basic Email Session Details is set to goes out of scope or the flow ends, whichever happens first. For more information about variables and scope, please see Variables.
For information on how to open a session, please see Opening Sessions.
Known Limitations
Currently unauthenticated SMTP servers are not supported.
This limitation may be removed in the future.
6.3.6 - Exceptions
Blocks related to handling and throwing Exceptions.
6.3.6.1 - Handle Block Exception(s)
Handle exceptions that occur during block execution.
6.3.6.1.1 - Handle Block Exception
Handles any exception thrown by the block it is connected to.
Handles any Exception thrown by the block it is connected to.
Examples
Handle and save the Exception
This example will handle any exception thrown by the block it is connected to; saving the exception to a variable, so the flow execution can use it to make decisions or take further action.
($)Exception is a variable that will be set to a dynamic value
Result
The block will handle any exception and save the exception to the ($)Exception variable for use later in the flow execution.
Handle and discard the Exception from being saved
This example will handle any exception thrown by the block it is connected to; not saving the exception to a variable, as the flow execution does not need it to make decisions or take further action.
Each block has an input port on its left-hand side and, with the exception of this block, also have an output port on their right-hand side; this is so they can pass any exception they do not handle to the next block.
As this block handles any exception, it does not require the output port.
For more information about chaining of exception handling blocks and passing of exceptions, please see Exception Handling.
Why does the Exception property return a dynamic data type?
The decision for the Exception to return a dynamic data type rather than an Exception data type, was to avoid users having to cast the exception to its correct type to be able to use all of its properties.
As a result, any issues with using the Exception data type (i.e. trying to access a property it does not have) will not be reported as messages when trying to debug the flow; they will only be discovered when the flow execution reaches the part of the flow with the issue.
If it is desirable to have any issues reported as messages when trying to debug the flow, the user can cast the exception to its correct type.
Using the built-in ($)_ variable to discard the Exception from being saved
Sometimes when an exception occurs the flow execution wants to use the exception to make decisions or take further action. However, there are occasions when the exception is not needed, and being forced to create another variable to save the exception is extra work for no benefit. In these circumstances it is possible to use the built-in ($)_ variable to indicate the exception does not need to be saved.
Handles any Exception thrown by the block it is connected to that matches a specified Message.
Examples
Handle Exception containing Message and save the Exception
This example will handle any exception thrown by the block it is connected to that contains "'List' is null" in its Message property; saving the exception to a variable, so the flow execution can use it to make decisions or take further action.
($)Exception is a variable that will be set to a dynamic value
Result
The block will handle any exception containing "'List' is null" in its Message property and save the exception to the ($)Exception variable for use later in the flow execution.
E.g.
If the List property of the Add Item At Beginning list block was set to null, it would throw a PropertyNullException when executed.
This exception’s Message property would be "'List' is null; it must be provided with a non-null value.\r\nPlease click the HelpLink for more information on how to fix this."; therefore as we are checking for exceptions containing "'List' is null" in their Message, this exception would be handled and saved to the ($)Exception variable.
Handle Exception containing Message and discard the Exception
This example is the same as the example above, except it does not save the exception to a variable, as the flow execution does not need it to make decisions or take further action.
($)_ is a built-in variable that indicates the flow execution does not need to save the exception, so it can be discarded
Result
The block will handle any exception containing "'List' is null" in its Message property, but will not save the exception as the ($)_ variable indicates it is not needed and can be discarded.
E.g.
If the List property of the Add Item At Beginning list block was set to null, it would throw a PropertyNullException when executed.
This exception’s Message property would be "'List' is null; it must be provided with a non-null value.\r\nPlease click the HelpLink for more information on how to fix this."; therefore as we are checking for exceptions containing "'List' is null" in their Message, this exception would be handled, but because the ($)_ variable is used it will not be saved to the ($)Exception variable.
This example will not handle an exception thrown by the block it is connected to that does not contain "'List' is null" in its Message property; the exception will be passed to the next exception handling block.
The block will not handle any exception that does not contain "'List' is null" in its Message property; instead the exception will be passed to the next exception handling block.
E.g.
If the List property of the Add Item At Beginning list block was set to a read-only List, it would throw a CannotModifyReadOnlyListException when executed.
This exception’s Message property would be "'List' cannot be modified because it's read-only.\r\nPlease click the HelpLink for more information on how to fix this."; therefore as we are checking for exceptions containing "'List' is null" in their Message, this exception would not be handled.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null or empty Message
If Message is null or empty (i.e. ""), and the thrown exception’s Message property is also null or empty (i.e. ""), the exception will be handled and saved to the variable specified in the Exception property.
Chaining Exception handling blocks
Blocks that handle block exceptions can be chained together so different exceptions can be handled separately. The blocks are listed below:
Each block has an input port on its left-hand side and, with the exception of the Handle Block Exception block, also have an output port on their right-hand side; this is so they can pass any exception they do not handle to the next block.
As the Handle Block Exception block handles any exception, it does not require the output port.
For more information about chaining of exception handling blocks and passing of exceptions, please see Exception Handling.
Why does the Exception property return a dynamic data type?
The decision for the Exception to return a dynamic data type rather than an Exception data type, was to avoid users having to cast the exception to its correct type to be able to use all of its properties.
As a result, any issues with using the Exception data type (i.e. trying to access a property it does not have) will not be reported as messages when trying to debug the flow; they will only be discovered when the flow execution reaches the part of the flow with the issue.
If it is desirable to have any issues reported as messages when trying to debug the flow, the user can cast the exception to its correct type.
Using the built-in ($)_ variable to discard the Exception from being saved
Sometimes when an exception occurs the flow execution wants to use the exception to make decisions or take further action. However, there are occasions when the exception is not needed, and being forced to create another variable to save the exception is extra work for no benefit. In these circumstances it is possible to use the built-in ($)_ variable to indicate the exception does not need to be saved.
Handles any Exception thrown by the block it is connected to that matches any message in a given set of Messages.
Examples
Handle Exception containing any of the Messages and save the Exception
This example will handle any exception thrown by the block it is connected to that contains any of the messages in ["'List' is null", "'List' is empty"] in its Message property; saving the exception to a variable, so the flow execution can use it to make decisions or take further action.
($)Exception is a variable that will be set to a dynamic value
Result
The block will handle any exception containing any of the messages in ["'List' is null", "'List' is empty"] in its Message property and save the exception to the ($)Exception variable for use later in the flow execution.
E.g.
If the List property of the Add Item At Beginning list block was set to null, it would throw a PropertyNullException when executed.
This exception’s Message property would be "'List' is null; it must be provided with a non-null value.\r\nPlease click the HelpLink for more information on how to fix this."; therefore as we are checking for exceptions containing any of ["'List' is null", "'List' is empty"] in their Message, this exception would be handled and saved to the ($)Exception variable.
Handle Exception containing any of the Messages and discard the Exception
This example is the same as the example above, except it does not save the exception to a variable, as the flow execution does not need it to make decisions or take further action.
($)_ is a built-in variable that indicates the flow execution does not need to save the exception, so it can be discarded
Result
The block will handle any exception containing any of the messages in ["'List' is null", "'List' is empty"] in its Message property, but will not save the exception as the ($)_ variable indicates it is not needed and can be discarded.
E.g.
If the List property of the Add Item At Beginning list block was set to null, it would throw a PropertyNullException when executed.
This exception’s Message property would be "'List' is null; it must be provided with a non-null value.\r\nPlease click the HelpLink for more information on how to fix this."; therefore as we are checking for exceptions containing any of ["'List' is null", "'List' is empty"] in their Message, this exception would be handled, but because the ($)_ variable is used it will not be saved to the ($)Exception variable.
This example will not handle an exception thrown by the block it is connected to that does not contain any of ["'List' is null", "'List' is empty"] in its Message property; the exception will be passed to the next exception handling block.
The block will not handle any exception that does not contain any of ["'List' is null", "'List' is empty"] in its Message property; instead the exception will be passed to the next exception handling block.
E.g.
If the List property of the Add Item At Beginning list block was set to a read-only List, it would throw a CannotModifyReadOnlyListException when executed.
This exception’s Message property would be "'List' cannot be modified because it's read-only.\r\nPlease click the HelpLink for more information on how to fix this."; therefore as we are checking for exceptions containing any of ["'List' is null", "'List' is empty"] in their Message, this exception would not be handled.
The Comparison Type specifying the rules used to determine whether any of the Messages are contained in the Exception’sMessage property.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null or empty Message in Messages
If any message in Messages is null or empty (i.e. ""), and the thrown exception’s Message property is also null or empty (i.e. ""), the exception will be handled and saved to the variable specified in the Exception property.
Chaining Exception handling blocks
Blocks that handle block exceptions can be chained together so different exceptions can be handled separately. The blocks are listed below:
Each block has an input port on its left-hand side and, with the exception of the Handle Block Exception block, also have an output port on their right-hand side; this is so they can pass any exception they do not handle to the next block.
As the Handle Block Exception block handles any exception, it does not require the output port.
For more information about chaining of exception handling blocks and passing of exceptions, please see Exception Handling.
Why does the Exception property return a dynamic data type?
The decision for the Exception to return a dynamic data type rather than an Exception data type, was to avoid users having to cast the exception to its correct type to be able to use all of its properties.
As a result, any issues with using the Exception data type (i.e. trying to access a property it does not have) will not be reported as messages when trying to debug the flow; they will only be discovered when the flow execution reaches the part of the flow with the issue.
If it is desirable to have any issues reported as messages when trying to debug the flow, the user can cast the exception to its correct type.
Using the built-in ($)_ variable to discard the Exception from being saved
Sometimes when an exception occurs the flow execution wants to use the exception to make decisions or take further action. However, there are occasions when the exception is not needed, and being forced to create another variable to save the exception is extra work for no benefit. In these circumstances it is possible to use the built-in ($)_ variable to indicate the exception does not need to be saved.
Handles any Exception thrown by the block it is connected to that matches a specified Type Name.
Examples
Handle Exception matching Type Name and save the Exception
This example will handle any exception thrown by the block it is connected to that contains "PropertyNull" in its fully qualified TypeName; saving the exception to a variable, so the flow execution can use it to make decisions or take further action.
($)Exception is a variable that will be set to a dynamic value
Result
The block will handle any exception containing "PropertyNull" in its fully qualified TypeName and save the exception to the ($)Exception variable for use later in the flow execution.
E.g.
If the List property of the Add Item At Beginning list block was set to null, it would throw a PropertyNullException when executed.
This exception’s fully qualified TypeName is "Cortex.Exceptions.Common.Property.PropertyNullException"; therefore as we are checking for exceptions containing "PropertyNull" in their TypeName, this exception would be handled and saved to the ($)Exception variable.
Handle Exception matching Type Name and discard the Exception
This example is the same as the example above, except it does not save the exception to a variable, as the flow execution does not need it to make decisions or take further action.
($)_ is a built-in variable that indicates the flow execution does not need to save the exception, so it can be discarded
Result
The block will handle any exception containing "PropertyNull" in its fully qualified TypeName, but will not save the exception as the ($)_ variable indicates it is not needed and can be discarded.
E.g.
If the List property of the Add Item At Beginning list block was set to null, it would throw a PropertyNullException when executed.
This exception’s fully qualified TypeName is "Cortex.Exceptions.Common.Property.PropertyNullException"; therefore as we are checking for exceptions containing "PropertyNull" in their TypeName, this exception would be handled, but because the ($)_ variable is used it will not be saved to the ($)Exception variable.
This example will not handle an exception thrown by the block it is connected to that does not contain "PropertyNull" in its fully qualified TypeName; the exception will be passed to the next exception handling block.
The block will not handle any exception that does not contain "PropertyNull" in its fully qualified TypeName; instead the exception will be passed to the next exception handling block.
E.g.
If the List property of the Add Item At Beginning list block was set to a read-only List, it would throw a CannotModifyReadOnlyListException when executed.
This exception’s fully qualified TypeName is "Cortex.Exceptions.Lists.CannotModifyReadOnlyListException"; therefore as we are checking for exceptions containing "PropertyNull" in their TypeName, this exception would not be handled.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Chaining Exception handling blocks
Blocks that handle block exceptions can be chained together so different exceptions can be handled separately. The blocks are listed below:
Each block has an input port on its left-hand side and, with the exception of the Handle Block Exception block, also have an output port on their right-hand side; this is so they can pass any exception they do not handle to the next block.
As the Handle Block Exception block handles any exception, it does not require the output port.
For more information about chaining of exception handling blocks and passing of exceptions, please see Exception Handling.
Why does the Exception property return a dynamic data type?
The decision for the Exception to return a dynamic data type rather than an Exception data type, was to avoid users having to cast the exception to its correct type to be able to use all of its properties.
As a result, any issues with using the Exception data type (i.e. trying to access a property it does not have) will not be reported as messages when trying to debug the flow; they will only be discovered when the flow execution reaches the part of the flow with the issue.
If it is desirable to have any issues reported as messages when trying to debug the flow, the user can cast the exception to its correct type.
Using the built-in ($)_ variable to discard the Exception from being saved
Sometimes when an exception occurs the flow execution wants to use the exception to make decisions or take further action. However, there are occasions when the exception is not needed, and being forced to create another variable to save the exception is extra work for no benefit. In these circumstances it is possible to use the built-in ($)_ variable to indicate the exception does not need to be saved.
Handles any Exception thrown by the block it is connected to that matches any type name in a given set of Type Names.
Examples
Handle Exception matching any of the Type Names and save the Exception
This example will handle any exception thrown by the block it is connected to that contains any of the type names in ["PropertyNull", "PropertyEmpty"] in its fully qualified TypeName; saving the exception to a variable, so the flow execution can use it to make decisions or take further action.
($)Exception is a variable that will be set to a dynamic value
Result
The block will handle any exception containing any of the type names in ["PropertyNull", "PropertyEmpty"] in its fully qualified TypeName and save the exception to the ($)Exception variable for use later in the flow execution.
E.g.
If the List property of the Add Item At Beginning list block was set to null, it would throw a PropertyNullException when executed.
This exception’s fully qualified TypeName is "Cortex.Exceptions.Common.Property.PropertyNullException"; therefore as we are checking for exceptions containing any of ["PropertyNull", "PropertyEmpty"] in their TypeName, this exception would be handled and saved to the ($)Exception variable.
Handle Exception containing any of the Type Names and discard the Exception
This example is the same as the example above, except it does not save the exception to a variable, as the flow execution does not need it to make decisions or take further action.
($)_ is a built-in variable that indicates the flow execution does not need to save the exception, so it can be discarded
Result
The block will handle any exception containing any of the type names in ["PropertyNull", "PropertyEmpty"] in its fully qualified TypeName, but will not save the exception as the ($)_ variable indicates it is not needed and can be discarded.
E.g.
If the List property of the Add Item At Beginning list block was set to null, it would throw a PropertyNullException when executed.
This exception’s fully qualified TypeName is "Cortex.Exceptions.Common.Property.PropertyNullException"; therefore as we are checking for exceptions containing any of ["PropertyNull", "PropertyEmpty"] in their TypeName, this exception would be handled, but because the ($)_ variable is used it will not be saved to the ($)Exception variable.
This example will not handle an exception thrown by the block it is connected to that does not contain any of ["PropertyNull", "PropertyEmpty"] in its fully qualified TypeName; the exception will be passed to the next exception handling block.
The block will not handle any exception that does not contain any of ["PropertyNull", "PropertyEmpty"] in its fully qualified TypeName; instead the exception will be passed to the next exception handling block.
E.g.
If the List property of the Add Item At Beginning list block was set to a read-only List, it would throw a CannotModifyReadOnlyListException when executed.
This exception’s fully qualified TypeName is "Cortex.Exceptions.Lists.CannotModifyReadOnlyListException"; therefore as we are checking for exceptions containing any of ["PropertyNull", "PropertyEmpty"] in their TypeName, this exception would not be handled.
The Comparison Type specifying the rules used to determine whether any of the Type Names are contained in the Exception’s fully qualified TypeName.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Chaining Exception handling blocks
Blocks that handle block exceptions can be chained together so different exceptions can be handled separately. The blocks are listed below:
Each block has an input port on its left-hand side and, with the exception of the Handle Block Exception block, also have an output port on their right-hand side; this is so they can pass any exception they do not handle to the next block.
As the Handle Block Exception block handles any exception, it does not require the output port.
For more information about chaining of exception handling blocks and passing of exceptions, please see Exception Handling.
Why does the Exception property return a dynamic data type?
The decision for the Exception to return a dynamic data type rather than an Exception data type, was to avoid users having to cast the exception to its correct type to be able to use all of its properties.
As a result, any issues with using the Exception data type (i.e. trying to access a property it does not have) will not be reported as messages when trying to debug the flow; they will only be discovered when the flow execution reaches the part of the flow with the issue.
If it is desirable to have any issues reported as messages when trying to debug the flow, the user can cast the exception to its correct type.
Using the built-in ($)_ variable to discard the Exception from being saved
Sometimes when an exception occurs the flow execution wants to use the exception to make decisions or take further action. However, there are occasions when the exception is not needed, and being forced to create another variable to save the exception is extra work for no benefit. In these circumstances it is possible to use the built-in ($)_ variable to indicate the exception does not need to be saved.
This example will handle any unhandled exception within the Flow; saving the exception to a variable, so the flow execution can use it to make decisions or take further action.
($)Exception is a variable that will be set to a dynamic value
Result
The block will handle any unhandled exception within the Flow and save the exception to the ($)Exception variable for use later in the flow execution.
Handle and discard the Exception from being saved
This example will handle any unhandled exception within the Flow; not saving the exception to a variable, as the flow execution does not need it to make decisions or take further action.
($)_ is a built-in variable that indicates the flow execution does not need to save the exception, so it can be discarded
Result
The block will handle any unhandled exception within the Flow, but will not save the exception as the ($)_ variable indicates it is not needed and can be discarded.
By default, this property is assigned the built-in ($)_ variable, so the exception will be discarded. If the flow execution does need the exception, a variable can be assigned to save it in.
If an exception occurs within the workspace of the Handle Flow Exception block and is not handled, the flow will end with a status of Error.
For more information about chaining of exception handling blocks and passing of exceptions, please see Exception Handling.
Why does the Exception property return a dynamic data type?
The decision for the Exception to return a dynamic data type rather than an Exception data type, was to avoid users having to cast the exception to its correct type to be able to use all of its properties.
As a result, any issues with using the Exception data type (i.e. trying to access a property it does not have) will not be reported as messages when trying to debug the flow; they will only be discovered when the flow execution reaches the part of the flow with the issue.
If it is desirable to have any issues reported as messages when trying to debug the flow, the user can cast the exception to its correct type.
Using the built-in ($)_ variable to discard the Exception from being saved
Sometimes when an exception occurs the flow execution wants to use the exception to make decisions or take further action. However, there are occasions when the exception is not needed, and being forced to create another variable to save the exception is extra work for no benefit. In these circumstances it is possible to use the built-in ($)_ variable to indicate the exception does not need to be saved.
This example will handle any unhandled exception within the block’s workspace; saving the exception to a variable, so the flow execution can use it to make decisions or take further action.
($)Exception is a variable that will be set to a dynamic value
Result
The block will handle any unhandled exception within the block’s workspace and save the exception to the ($)Exception variable for use later in the flow execution.
Handle and discard the Exception from being saved
This example will handle any unhandled exception within the block’s workspace; not saving the exception to a variable, as the flow execution does not need it to make decisions or take further action.
($)_ is a built-in variable that indicates the flow execution does not need to save the exception, so it can be discarded
Result
The block will handle any unhandled exception within the block’s workspace, but will not save the exception as the ($)_ variable indicates it is not needed and can be discarded.
A workspace cannot contain more than one Handle Workspace Exception block. If more than one is added, it will be reported as a message when trying to debug the flow.
The Handle Workspace Exception block will only handle the first unhandled exception within its workspace. This is to prevent infinite recursion within the flow. Subsequent unhandled exceptions are passed to the next relevant exception handling block. For more information about chaining of exception handling blocks and passing of exceptions, please see Exception Handling.
A flow’s Top-Level Workspace cannot contain a Handle Workspace Exception block. If one is added, it will be reported as a message when trying to debug the flow.
If an exception occurs within the workspace of the Handle Flow Exception block and is not handled, the flow will end with a status of Error.
For more information about chaining of exception handling blocks and passing of exceptions, please see Exception Handling.
Why does the Exception property return a dynamic data type?
The decision for the Exception to return a dynamic data type rather than an Exception data type, was to avoid users having to cast the exception to its correct type to be able to use all of its properties.
As a result, any issues with using the Exception data type (i.e. trying to access a property it does not have) will not be reported as messages when trying to debug the flow; they will only be discovered when the flow execution reaches the part of the flow with the issue.
If it is desirable to have any issues reported as messages when trying to debug the flow, the user can cast the exception to its correct type.
Using the built-in ($)_ variable to discard the Exception from being saved
Sometimes when an exception occurs the flow execution wants to use the exception to make decisions or take further action. However, there are occasions when the exception is not needed, and being forced to create another variable to save the exception is extra work for no benefit. In these circumstances it is possible to use the built-in ($)_ variable to indicate the exception does not need to be saved.
($)Exception, with value of{"Exception Type": "PropertyNullException","Message": "'List' is null; it must be provided with a non-null value.\r\nPlease click the HelpLink for more information on how to fix this.","HelpLink": "https://v2022.docs.cortex-ia.com/docs/reference/exceptions/common/property/property-null-exception"}
Sometimes it is necessary to propagate exceptions thrown in a child flow to the flow that called it. Currently, using the Rethrow Exception block to rethrow the Exception from the Handle Flow Exception workspace is the only way to achieve this. This can be seen below:
In future, additional ways to propagate exceptions between flows may be added.
6.3.6.5 - Throw Exception
Throw an exception.
6.3.6.5.1 - Throw New Flow Exception
Throws a new FlowException with the specified message, category, error code, details, inner exception and help link.
A Category that can be used to categorise similar types of exception that has occurred (e.g. an AuthenticationError category may be set for exceptions relating to authentication issues). This can then be used for future decision making in the flow, or to assist in troubleshooting and reporting.
An Error Code that can be used to uniquely identify the type of exception (e.g. There may be multiple exceptions with the same AuthenticationError category set, such as InvalidCredentials, TokenExpired. In this case each exception can be assigned its own unique Error Code; InvalidCredentials = 100 and TokenExpired = 101). This can then be used for future decision making in the flow, or to assist in troubleshooting and reporting.
If Error Code is not provided, it will default to null.
Details can be used to provide more detailed information about the exception. It can be any type of Object. This can then be used for future decision making in the flow, or to assist in troubleshooting and reporting.
A Help Link can be specified where further information can be found about the exception being thrown.
If Help Link is not provided or is set to null, it will default to a link to the FlowException page; please note this page will not provide any guidance on how to fix the solution specific exception.
If Message is not provided or is set to null, it will default to "Exception of type 'Cortex.Exceptions.Flows.FlowException' was thrown.".
Null Help Link
If Help Link is not provided or is set to null, it will default to a link to the FlowException page, please note this page will not provide any guidance on how to fix the solution specific exception.
6.3.7 - Files & Folders
Blocks related to working with Files and Folders.
6.3.7.1 - Check File Exists
Check if a file exists.
6.3.7.1.1 - Check File Exists
Checks if a file exists at the specified file path.
($)FileExists is a variable that will be set to a Boolean value
Result
"C:\Windows\System32\cmd.exe" is the command prompt application on Windows machines. Checking this on the Windows server executing the flow will result in the variable ($)FileExists being updated to the following:
true
File does not exist at the specified File Path
This example will check if "/etc/passwd" exists on the Windows server executing the flow.
($)FileExists is a variable that will be set to a Boolean value
Result
"/etc/passwd" is a file that exists on Linux machines containing the list of system accounts. Checking this on the Windows server executing the flow will result in the variable ($)FileExists being updated to the following:
For information about the supported file path formats (i.e. absolute, relative, UNC etc.) and examples of each, please see File & Folder Paths.
File Path needs escaping
File Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Windows\\System32\\cmd.exe"), or
Prepending an @ character before the start of the File Path (e.g. @"C:\Windows\System32\cmd.exe")
Null File Path
If File Path is null the variable specified in the File Exists property will be set to false.
Empty File Path
If File Path is empty (i.e. "") the variable specified in the File Exists property will be set to false.
Invalid File Path
If File Path is invalid (i.e. contains any of the following characters: ", *, ?, |, <, >, :, \, /) the variable specified in the File Exists property will be set to false.
File Path points to a folder
If File Path points to a folder, the variable specified in the File Exists property will be set to false.
If File Path contains leading spaces they are not removed; however, trailing spaces are removed.
Error occurs whilst checking if the file exists
If any error occurs whilst checking if a file exists at the specified File Path, the variable specified in the File Exists property will be set to false.
User does not have necessary permissions to check if the file exists
If the user the flow is executing as does not have permissions to check if a file exists at the specified File Path, the variable specified in the File Exists property will be set to false.
6.3.7.2 - Check Folder Exists
Check if a folder exists.
6.3.7.2.1 - Check Folder Exists
Checks if a folder exists at the specified folder path.
($)FolderExists is a variable that will be set to a Boolean value
Result
"C:\Windows\System32" is the folder on Windows machines that contains files critical to the functioning of the operating system. Checking this on the Windows server executing the flow will result in the variable ($)FolderExists being updated to the following:
true
Folder does not exist at the specified Folder Path
This example will check if "/etc" exists on the Windows server executing the flow.
($)FolderExists is a variable that will be set to a Boolean value
Result
"/etc" is the folder on Linux machines containing system configuration files. Checking this on the Windows server executing the flow will result in the variable ($)FolderExists being updated to the following:
The Folder Path is case-insensitive, any trailing spaces will be automatically removed, and can end with or without a trailing \ (e.g. @"C:\Windows\System32" or @"C:\Windows\System32\").
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, please see File & Folder Paths.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, please see File & Folder Paths.
Folder Path needs escaping
Folder Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Windows\\System32"), or
Prepending an @ character before the start of the Folder Path (e.g. @"C:\Windows\System32")
Null Folder Path
If Folder Path is null the variable specified in the Folder Exists property will be set to false.
Empty Folder Path
If Folder Path is empty (i.e. "") the variable specified in the Folder Exists property will be set to false.
Invalid Folder Path
If Folder Path is invalid (i.e. contains any of the following characters: ", *, ?, |, <, >, :, \, /) the variable specified in the Folder Exists property will be set to false.
Folder Path points to a file
If Folder Path points to a file, the variable specified in the Folder Exists property will be set to false.
If Folder Path contains leading spaces they are not removed; however, trailing spaces are removed.
Error occurs whilst checking if the folder exists
If any error occurs whilst checking if a folder exists at the specified Folder Path, the variable specified in the Folder Exists property will be set to false.
User does not have necessary permissions to check if the folder exists
If the user the flow is executing as does not have permissions to check if a folder exists at the specified Folder Path, the variable specified in the Folder Exists property will be set to false.
6.3.7.3 - Copy File(s)
Copy a file or multiple files.
6.3.7.3.1 - Copy File
Copies a file at the specified file path to the given destination path.
Copy a file to a folder keeping the same file name
This example will copy "C:\Source\OriginalFile.txt" to "C:\Destination", with the same file name of "OriginalFile.txt".
In this example assume "C:\Destination" does not already contain a file named "OriginalFile.txt", so overwrite can be set to either true or false and it will still work.
Copying "C:\Source\OriginalFile.txt" to "C:\Destination" that does not already contain a file named "OriginalFile.txt" will:
Create a new file at "C:\Destination\OriginalFile.txt" with:
The content copied from "C:\Source\OriginalFile.txt".
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\OriginalFile.txt".
The File Attributes copied from "C:\Source\OriginalFile.txt".
Copy a file to a folder with a new name
This example will copy "C:\Source\OriginalFile.txt" to "C:\Destination", with a new file name of "NewFile.txt".
To rename the file when it is being copied, please note that the Destination Path must be a file path, rather than a folder path (e.g. "C:\Destination\NewFile.txt" rather than "C:\Destination").
In this example assume "C:\Destination" does not already contain a file named "NewFile.txt", so overwrite can be set to either true or false and it will still work.
Copying "C:\Source\OriginalFile.txt" to the path "C:\Destination\NewFile.txt" that does not already exist will:
Create a new file at "C:\Destination\NewFile.txt" with:
The content copied from "C:\Source\OriginalFile.txt".
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\OriginalFile.txt".
The File Attributes copied from "C:\Source\OriginalFile.txt".
Copy a file to a folder overwriting any file that already exists with the same name
This example will copy "C:\Source\FileAlreadyExists.txt" to "C:\Destination", with the same file name of "FileAlreadyExists.txt".
In this example assume "C:\Destination" already contains a file named "FileAlreadyExists.txt", so overwrite must be set to true to ensure the content of the existing file can be overwritten.
If it points to a folder, the copied file will have the name specified in the File Path.
If it points to a file, the copied file will have the name specified in the Destination Path.
Any non-existing folders within the Destination Path will be automatically created.
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
If the file exists, Overwrite must be set to true, otherwise an OperationFailedException will be thrown. By default, this is set to false to avoid implicit and accidental overwriting of existing files.
The Destination Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The Destination Path (if it points to a file), or the Destination Path (if it points to a folder) plus the file name, exceeds the system-defined maximum length (typically 32,767 characters).
The File Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The File Path exceeds the system-defined maximum length (typically 32,767 characters).
The file in the specified Destination Path exists and overwrite is false.
The file in the specified Destination Path exists, is read-only and overwrite is true.
The file in the specified Destination Path exists, is hidden and overwrite is true, but the file in the specified File Path is not hidden.
The user the flow is executing as does not have the required permissions to copy the file (e.g. not having read access to the File Path or write access to the Destination Path).
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Path and Destination Path need escaping
File Path and Destination Path require \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\OriginalFile.txt"), or
Prepending an @ character before the start of the File Path (e.g. @"C:\Source\OriginalFile.txt") and Destination Path (e.g. @"C:\Destination").
File Attributes
When copying a file from the File Path to the new Destination Path, all of the file’s attributes will also be copied.
For information about the file attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
6.3.7.3.2 - Copy Files
Copies files at the specified file paths to the given destination path.
Copy files to a folder keeping the same file names
This example will copy ["C:\Source\OriginalFile1.txt", "C:\Source\OriginalFile2.txt"] to "C:\Destination", with the same file names of "OriginalFile1.txt" and "OriginalFile2.txt".
In this example assume "C:\Destination" does not already contain a file named "OriginalFile1.txt" or a file named "OriginalFile2.txt", so overwrite can be set to either true or false and it will still work.
Copying ["C:\Source\OriginalFile1.txt", "C:\Source\OriginalFile2.txt"] to "C:\Destination" that does not already contain files named "OriginalFile1.txt" and "OriginalFile2.txt" will:
Create a new file at "C:\Destination\OriginalFile1.txt" with:
The content copied from "C:\Source\OriginalFile1.txt".
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\OriginalFile1.txt".
The File Attributes copied from "C:\Source\OriginalFile1.txt".
Create a new file at "C:\Destination\OriginalFile2.txt" with:
The content copied from "C:\Source\OriginalFile2.txt".
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\OriginalFile2.txt".
The File Attributes copied from "C:\Source\OriginalFile2.txt".
Copy files to a folder overwriting any files that already exists with the same names
This example will copy ["C:\Source\FileAlreadyExists1.txt", "C:\Source\FileAlreadyExists2.txt"] to "C:\Destination", with the same file names of "FileAlreadyExists1.txt" and "FileAlreadyExists2.txt".
In this example assume "C:\Destination" already contains a file named "FileAlreadyExists1.txt" and a file named "FileAlreadyExists2.txt", so overwrite must be set to true to ensure the content of the existing files can be overwritten.
Copying ["C:\Source\FileAlreadyExists1.txt", "C:\Source\FileAlreadyExists2.txt"] to "C:\Destination" and overwriting the existing files named "FileAlreadyExists1.txt" and "FileAlreadyExists2.txt" will:
Overwrite the existing file at "C:\Destination\FileAlreadyExists1.txt" with:
The content copied from "C:\Source\FileAlreadyExists1.txt".
The Date Created left unchanged.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\FileAlreadyExists1.txt".
The File Attributes copied from "C:\Source\FileAlreadyExists1.txt".
Overwrite the existing file at "C:\Destination\FileAlreadyExists2.txt" with:
The content copied from "C:\Source\FileAlreadyExists2.txt".
The Date Created left unchanged.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\FileAlreadyExists2.txt".
The File Attributes copied from "C:\Source\FileAlreadyExists2.txt".
The copied files will have the names specified in the File Paths.
Any non-existing folders within the Destination Path will be automatically created.
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
If any file exists, Overwrite must be set to true, otherwise an OperationFailedException will be thrown. By default, this is set to false to avoid implicit and accidental overwriting of existing files.
The Destination Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The Destination Path (if it points to a file), or the Destination Path (if it points to a folder) plus the file name, exceeds the system-defined maximum length (typically 32,767 characters).
Any file path in File Paths contains leading spaces.
Any file path in File Paths contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
Any file path in File Paths exceeds the system-defined maximum length (typically 32,767 characters).
Any file path in File Paths exists in the specified Destination Path with the same name, is read-only and overwrite is true.
Any file path in File Paths exists in the specified Destination Path with the same name, is hidden and overwrite is true, but the file in the specified File Paths is not hidden.
The user the flow is executing as does not have the required permissions to copy any file (e.g. not having read access to a file path in File Paths or write access to the Destination Path).
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Paths and Destination Path need escaping
Each file path in File Paths and Destination Path require \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\OriginalFile.txt"), or
Prepending an @ character before the start of the
file path (e.g. @"C:\Source\OriginalFile.txt") and Destination Path (e.g. @"C:\Destination").
File Attributes
When copying a file in the File Paths to the new Destination Path, all of the file’s attributes will also be copied.
For information about the file attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
Handling of Exceptions
If an exception occurs when trying to copy a file in the File Paths, it will be recorded and the block will continue processing the remaining files. Once all files are processed, recorded exceptions will be thrown within an OperationFailedException.
6.3.7.4 - Copy Folder(s)
Copy a folder or multiple folders.
6.3.7.4.1 - Copy Folder
Copies a folder at the specified folder path to the given destination path.
Copying "C:\Source\Folder" and its content to "C:\Destination" with the Overwrite option set to true, and where "C:\Destination\Folder", "C:\Destination\Folder\SubFolderAlreadyExists" and "C:\Destination\Folder\FileAlreadyExists.txt" already exist will:
Overwrite the existing folder at "C:\Destination\Folder" with:
Create a new file at "C:\Destination\Folder\File.txt" with:
The content copied from "C:\Source\Folder\File.txt".
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\Folder\File.txt".
The File attributes copied from "C:\Source\Folder\File.txt".
Overwrite the existing file at "C:\Destination\Folder\FileAlreadyExists.txt" with:
The content copied from "C:\Source\Folder\FileAlreadyExists.txt".
The Date Created left unchanged.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\Folder\FileAlreadyExists.txt".
The File attributes copied from "C:\Source\Folder\FileAlreadyExists.txt".
Copy a folder’s content only
This example will copy "C:\Source\Folder" content only to "C:\Destination".
In this example assume:
"C:\Source\Folder" contains:
An empty sub-folder named "SubFolder".
A file named "File.txt".
"C:\Destination" does not already contain a folder named "SubFolder" or a file named "File.txt", so overwrite can be set to either true or false and it will still work.
Copying "C:\Source\Folder" content only to "C:\Destination" with the Overwrite option set to true, and where "C:\Destination\SubFolderAlreadyExists" and "C:\Destination\FileAlreadyExists.txt" already exist will:
Create a new empty folder at "C:\Destination\SubFolder" with:
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified set to the time the copy occurred.
Create a new file at "C:\Destination\File.txt" with:
The content copied from "C:\Source\Folder\File.txt".
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\Folder\File.txt".
The File attributes copied from "C:\Source\Folder\File.txt".
Overwrite the existing file at "C:\Destination\FileAlreadyExists.txt" with:
The content copied from "C:\Source\Folder\FileAlreadyExists.txt".
The Date Created left unchanged.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\Folder\FileAlreadyExists.txt".
The File attributes copied from "C:\Source\Folder\FileAlreadyExists.txt".
Copy a folder and its content to the same location but with a different name
If it is required to copy a folder and its content into the same folder it is currently located in, but with a different name, then it is not possible to do with this block; the Duplicate Folder block must be used instead.
Copy a folder and its content to a different location but with a different name
If it is required to copy a folder and its content into a different folder than the one it is currently located in, but with a different name, then it is not possible to do with this block; the Rename Folder block must be used instead.
Properties
Folder Path
The Folder Path to copy the folder and/or its content from.
The Folder Path is case-insensitive, cannot contain any wildcard characters, and any trailing spaces will be automatically removed.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, please see File & Folder Paths.
The copied folders and files will have the same names as the folders and files copied.
Any non-existing folders within the Destination Path will be automatically created.
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Option to Overwrite the folder and/or contents being copied to in the Destination Path if they already exist.
If the folder and/or contents exists, Overwrite must be set to true, otherwise an OperationFailedException will be thrown. By default, this is set to false to avoid implicit and accidental overwriting of existing folders and files.
The Destination Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Destination Path exceeds the system-defined maximum length (typically 32,767 characters).
The Folder Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Folder Path exceeds the system-defined maximum length (typically 32,767 characters).
Any file being copied already exists in the specified Destination Path and overwrite is false.
Any file being copied already exists in the specified Destination Path, is read-only and overwrite is true.
Any file being copied already exists in the specified Destination Path, is hidden and overwrite is true, but the file under the specified Folder Path is not hidden.
The user the flow is executing as does not have the required permissions to copy the folder or any of its content (e.g. not having read access to the Folder Path or its content, or write access to the Destination Path).
The operation is cyclic (e.g. copying a folder into one of its sub-folders).
An unexpected error occurs when copying the folder or any of its content.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Path and Destination Path need escaping
Folder Path and Destination Path require \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the Folder Path (e.g. @"C:\Source") and Destination Path (e.g. @"C:\Destination").
Folder Attributes
When copying the folder at the specified Folder Path or any folder under it to the new Destination Path, if the copied folder already exists its attributes remain unchanged, otherwise they are copied.
For information about the folder attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
File Attributes
When copying a file under Folder Path to the new Destination Path, all of the file’s attributes are also copied.
For information about the file attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
An option can also be specified to Overwrite anything being copied that already exists in the Destination Path.
Examples
Copy folders and their content
This example will copy ["C:\Source\Folder1", "C:\Source\Folder2"] and their content to "C:\Destination".
In this example assume:
"C:\Source\Folder1" contains:
An empty sub-folder named "SubFolder1".
A file named "File1.txt".
"C:\Source\Folder2" contains:
An empty sub-folder named "SubFolder2".
A file named "File2.txt".
"C:\Destination" does not already contain a folder named "Folder1" or "Folder2", so overwrite can be set to either true or false and it will still work.
Copying ["C:\Source\Folder1", "C:\Source\Folder2"] and their content to "C:\Destination" that does not already contain folders named "Folder1" and "Folder2" will:
Create a new folder at "C:\Destination\Folder1" with:
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified set to the time the copy occurred.
Copying ["C:\Source\Folder1", "C:\Source\Folder2"] and their content to "C:\Destination" with the Overwrite option set to true, and where "C:\Destination\Folder1", "C:\Destination\Folder1\SubFolderAlreadyExists1", "C:\Destination\Folder1\FileAlreadyExists1.txt", "C:\Destination\Folder2", "C:\Destination\Folder2\SubFolderAlreadyExists2" and "C:\Destination\Folder2\FileAlreadyExists2.txt" already exist will:
Overwrite the existing folder at "C:\Destination\Folder1" with:
Create a new file at "C:\Destination\Folder2\File2.txt" with:
The content copied from "C:\Source\Folder2\File2.txt".
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\Folder2\File2.txt".
The File attributes copied from "C:\Source\Folder2\File2.txt".
Overwrite the existing file at "C:\Destination\Folder2\FileAlreadyExists2.txt" with:
The content copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The Date Created left unchanged.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The File attributes copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
Copy the folders’ content only
This example will copy ["C:\Source\Folder1", "C:\Source\Folder2"] content only to "C:\Destination".
In this example assume:
"C:\Source\Folder1" contains:
An empty sub-folder named "SubFolder1".
A file named "File1.txt".
"C:\Source\Folder2" contains:
An empty sub-folder named "SubFolder2".
A file named "File2.txt".
"C:\Destination" does not already contain a folder named "SubFolder1" or "SubFolder2" or a file named "File1.txt" or "File2.txt", so overwrite can be set to either true or false and it will still work.
Copying ["C:\Source\Folder1", "C:\Source\Folder2"] content only to "C:\Destination" that does not already contain a folder named "SubFolder1" or "SubFolder2" or a file named "File1.txt" or "File2.txt" will:
Create a new folder at "C:\Destination\SubFolder1" with:
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified set to the time the copy occurred.
Copying ["C:\Source\Folder1", "C:\Source\Folder2"] content only to "C:\Destination" with the Overwrite option set to true, and where "C:\Destination\SubFolderAlreadyExists1", "C:\Destination\SubFolderAlreadyExists2", "C:\Destination\FileAlreadyExists1.txt" and "C:\Destination\FileAlreadyExists2.txt" already exist will:
Create a new empty folder at "C:\Destination\SubFolder1" with:
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified set to the time the copy occurred.
Create a new file at "C:\Destination\File2.txt" with:
The content copied from "C:\Source\Folder2\File2.txt".
The Date Created set to the time the copy occurred.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\Folder2\File2.txt".
The File attributes copied from "C:\Source\Folder2\File2.txt".
Overwrite the existing file at "C:\Destination\FileAlreadyExists2.txt" with:
The content copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The Date Created left unchanged.
The Date Accessed set to the time the copy occurred.
The Date Modified copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The File attributes copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
Copy folders and their content to the same location but with a different name
If it is required to copy folders and their content into the same folder they are currently located in, but with a different name, then it is not possible to do with this block; the Duplicate Folder block must be used instead.
Copy folders and their content to a different location but with a different name
If it is required to copy folders and their content into a different folder than the one they are currently located in, but with a different name, then it is not possible to do with this block; the Rename Folder block must be used instead.
Properties
Folder Paths
The Folder Paths to copy the folders and/or their content from.
Each folder path in Folder Paths is case-insensitive, cannot contain any wildcard characters, and any trailing spaces will be automatically removed.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, please see File & Folder Paths.
The copied folders and files will have the same names as the folders and files copied.
Any non-existing folders within the Destination Path will be automatically created.
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Option to Overwrite the folders and/or contents being copied to in the Destination Path if they already exist.
If any of the folders and/or contents exists, Overwrite must be set to true, otherwise an OperationFailedException will be thrown. By default, this is set to false to avoid implicit and accidental overwriting of existing folders and files.
The Destination Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Destination Path exceeds the system-defined maximum length (typically 32,767 characters).
Any folder path in Folder Paths contains leading spaces.
Any folder path in Folder Paths contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
Any folder path in Folder Paths exceeds the system-defined maximum length (typically 32,767 characters).
Any file being copied already exists in the specified Destination Path and overwrite is false.
Any file being copied already exists in the specified Destination Path, is read-only and overwrite is true.
Any file being copied already exists in the specified Destination Path, is hidden and overwrite is true, but the file under any of the specified Folder Paths is not hidden.
The user the flow is executing as does not have the required permissions to copy the folder or any of its content (e.g. not having read access to any of the folders in Folder Paths or its content, or write access to the Destination Path).
The operation is cyclic (e.g. copying a folder into one of its sub-folders).
An unexpected error occurs when copying a folder or any of its content.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Path and Destination Path need escaping
Each folder paths in Folder Paths and Destination Path require \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the folder path (e.g. @"C:\Source") and Destination Path (e.g. @"C:\Destination").
Folder Attributes
When copying the folders at the specified Folder Paths or any folder under them to the new Destination Path, if the copied folder already exists its attributes remain unchanged, otherwise they are copied.
For information about the folder attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
File Attributes
When copying a file under any of the Folder Paths to the new Destination Path, all of the file’s attributes are also copied.
For information about the file attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
Conflicting Content
If two or more paths in the specified Folder Paths contain content (folders or files) with the same name, and Overwrite and Content Only are true:
The attributes of the folder/file in the Destination Path will be that of the first one copied.
For files, the content of the file in the Destination Path will be that of the last one copied.
Handling of Exceptions
If an exception occurs when trying to copy a folder in Folder Paths, it will be recorded and the block will continue processing the remaining folders. Once all folders are processed, recorded exceptions will be thrown within an OperationFailedException.
6.3.7.4.3 - Duplicate Folder
Copies a folder at the specified folder path to the same location but with a new name.
The Folder Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Folder Path exceeds the system-defined maximum length (typically 32,767 characters).
The Folder Path is a win32 device path (i.e starts with a "\\.\").
The Folder Path is invalid (for example, it is on an unmapped drive).
The user the flow is executing as does not have the required permissions to copy the folder or any of its content (e.g. not having read access to the Folder Path or its content, or write access to the parent of Folder Path.
An unexpected error occurs when copying the folder or any of its content.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Path needs escaping
Folder Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the Folder Path (e.g. @"C:\Source").
Folder Attributes
When copying the folder at or any folder under the specified Folder Path all of the folder’s attributes are also copied.
For information about the folder attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
File Attributes
When copying a file under Folder Path all of the file’s attributes are also copied.
For information about the file attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
The Folder Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Folder Path exceeds the system-defined maximum length (typically 32,767 characters).
The Folder Path is invalid (for example, it is on an unmapped drive).
The user the flow is executing as does not have the required permissions to create the folder at the Folder Path.
An unexpected error occurs when creating the folder at the Folder Path or any of its content.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Path needs escaping
Folder Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the Folder Path (e.g. @"C:\Source").
Folder Path already exists
If the Folder Path already exists nothing is created, and no exception is thrown.
Any folder path in Folder Paths contains leading spaces.
Any folder path in Folder Paths contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
Any folder path in Folder Paths exceeds the system-defined maximum length (typically 32,767 characters).
Any folder path in Folder Paths is invalid (for example, it is on an unmapped drive).
The user the flow is executing as does not have the required permissions to create a folder in the Folder Paths.
An unexpected error occurs when creating a folder in the Folder Paths or any of its content.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Paths need escaping
Each folder path in Folder Paths requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the folder path (e.g. @"C:\Source").
Folder Path already exists
If a folder path in Folder Paths already exists nothing is created, and no exception is thrown.
Handling of Exceptions
If an exception occurs when trying to create a folder in Folder Paths, it will be recorded and the block will continue processing the remaining folders. Once all folders are processed, recorded exceptions will be thrown within an OperationFailedException.
The File Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The File Path exceeds the system-defined maximum length (typically 32,767 characters).
The File Path is invalid (for example, it is on an unmapped drive).
For information about the supported file path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Path needs escaping
File Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\File.txt"), or
Prepending an @ character before the start of the File Path (e.g. @"C:\Source\File.txt").
File Path does not exist
If the File Path does not exist nothing is deleted, and no exception is thrown.
Any file path in File Paths contains leading spaces.
Any file path in File Paths contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
Any file path in File Paths exceeds the system-defined maximum length (typically 32,767 characters).
Any file path in File Paths is invalid (for example, it is on an unmapped drive).
For information about the supported file path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Paths need escaping
Each file path in File Paths requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\File.txt"), or
Prepending an @ character before the start of the
file path (e.g. @"C:\Source\File.txt").
File Path does not exist
If a file path in File Paths does not exist no exception is recorded for that file path.
Handling of Exceptions
If an exception occurs when trying to delete a file in the File Paths, it will be recorded and the block will continue processing the remaining files. Once all files are processed, recorded exceptions will be thrown within an OperationFailedException.
A Recursive option must be set to true to be able to delete a folder that contains files and/or other folders. This is to prevent unintentional and destructive deletion of files and folders.
The Folder Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Folder Path exceeds the system-defined maximum length (typically 32,767 characters).
The folder at the Folder Path is not empty and recursive is false.
The folder at the Folder Path or any sub-folders are read-only or contain read-only files and/or folders.
The user the flow is executing as does not have the required permissions to delete the folder at the Folder Path or any of its content.
An unexpected error occurs when deleting the folder at the Folder Path or any of its content.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Path needs escaping
Folder Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the Folder Path (e.g. @"C:\Source").
Folder Path does not exist
If the Folder Path does not exist nothing is deleted, and no exception is thrown.
A Recursive option must be set to true to be able to delete folders that contain files and/or other folders. This is to prevent unintentional and destructive deletion of files and folders.
Examples
Delete empty folders
This example will delete ["C:\Source\EmptyFolder1", "C:\Source\EmptyFolder2"].
Deleting ["C:\Source\EmptyFolder1", "C:\Source\EmptyFolder2"] results in the folders "EmptyFolder1" and "EmptyFolder2" being deleted from the folder "C:\Source".
Delete folders and their content
This example will delete ["C:\Source\Folder1", "C:\Source\Folder2"] and their content.
In this example assume:
"C:\Source\Folder1" contains:
A file named "FileInFolder1.txt".
An empty sub-folder named "EmptySubFolder1".
An sub-folder named "SubFolder1" that contains.
A file named "FileInSubFolder1.txt".
"C:\Source\Folder2" contains:
A file named "FileInFolder2.txt".
An empty sub-folder named "EmptySubFolder2".
An sub-folder named "SubFolder2" that contains.
A file named "FileInSubFolder2.txt".
Therefore, recursive must be set to true to ensure child folders and files can be deleted.
Any folder path in Folder Paths contains leading spaces.
Any folder path in Folder Paths contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
Any folder path in Folder Paths exceeds the system-defined maximum length (typically 32,767 characters).
Any folder path in Folder Paths is not empty and recursive is false.
Any folder path in Folder Paths or any of their sub-folders are read-only or contain read-only files and/or folders.
The user the flow is executing as does not have the required permissions to delete a folder in the Folder Paths or any of its content.
An unexpected error occurs when deleting a folder in the Folder Paths or any of its content.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Paths need escaping
Each folder path in Folder Paths requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the folder path (e.g. @"C:\Source").
Folder Path does not exist
If a folder path in Folder Paths does not exist no exception is recorded for that folder path.
Handling of Exceptions
If an exception occurs when trying to delete a folder in Folder Paths, it will be recorded and the block will continue processing the remaining folders. Once all folders are processed, recorded exceptions will be thrown within an OperationFailedException.
6.3.7.8 - Get File Information
Get information about a file (i.e. file attributes, created, accessed and modified dates etc.).
6.3.7.8.1 - Get File Information
Gets information about a file (e.g. file attributes, created, accessed, modified dates etc.) at the specified file path.
The File Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder or file names.
The File Path exceeds the system-defined maximum length (typically 32,767 characters).
The File Path is invalid (for example, it is on an unmapped drive).
The user the flow is executing as does not have the required permissions to get information about the file at the File Path.
An unexpected error occurs when getting information for the file at the File Path.
For information about the supported file path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Path needs escaping
File Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\File.txt"), or
Prepending an @ character before the start of the File Path (e.g. @"C:\Source\File.txt").
6.3.7.9 - Get Folder Content
Get the paths of files or folders in another folder.
6.3.7.9.1 - Get Folder Content
Gets the paths of files or folders under the specified folder path.
The returned Paths can then be used in other file and folder blocks that require paths.
Additional options can be specified:
Search Options can be specified to choose whether to use a ContainsText, PatternMatching or Regex search.
Content Options can be specified to choose whether to search for files or folders.
A Recursive option can specified to choose whether to search only in the specified Folder Path, or include all subfolders.
A Comparison Type option can specified to choose how it is determined whether the file or folder name matches the Search Pattern (e.g. whether the search is case-sensitive or case-insensitive).
Examples
Get paths of files in a folder whose names contain a given text
This example will get the paths of all files in "C:\Source\Folder" that contain "file" in their name.
It will perform a case-insensitive search, and will not get any paths of folders or any paths of files that reside in subfolders of "C:\Source\Folder".
In this example assume "C:\Source\Folder" contains:
($)Paths is a variable that will be set to an IList<String> value
Result
Getting all file paths that contain "file" (case-insensitive) in "C:\Source\Folder" excluding any of its subfolders, results in the variable ($)Paths being updated to the following:
($)Paths is a variable that will be set to an IList<String> value
Result
Getting all file paths that contain "File" (case-sensitive) in "C:\Source\Folder" or any of its subfolders, results in the variable ($)Paths being updated to the following:
Get paths of folders in a folder whose names match a given pattern
This example will get the paths of all folders that are in "C:\Source\Folder", and match the pattern "*" in their name.
It will perform a case-insensitive search, will not get any paths of files, and will match any folder in "C:\Source\Folder". It will not match any child folders of folders in "C:\Source\Folder".
In this example assume "C:\Source\Folder" contains:
($)Paths is a variable that will be set to an IList<String> value
Result
Getting all folder paths that match the pattern "*" (case-insensitive) in "C:\Source\Folder" excluding any of its subfolders, results in the variable ($)Paths being updated to the following:
["C:\\Source\\Folder\\SubFolder"]
Get paths of folders in a folder (and its subfolders) whose names match a given regex
This example will get the paths of all folders that are in "C:\Source\Folder" or any of its subfolders, and match the regex "Folder$" in their name.
It will perform a case-sensitive search, will not get any paths of files, and will match folders whose name ends with "Folder".
In this example assume "C:\Source\Folder" contains:
($)Paths is a variable that will be set to an IList<String> value
Result
Getting all folder paths that match the regex "Folder$" (case-sensitive) in "C:\Source\Folder" or any of its subfolders, results in the variable ($)Paths being updated to the following:
Search Options can be specified to choose whether Search Pattern should be interpreted as a ContainsText, PatternMatching or Regex search:
SearchOptions.ContainsText matches text exactly; as long as the file or folder name contains the text specified in Search Pattern it will be considered a match.
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
All Paths that match the specified Search Pattern based on the other specified options.
The Paths returned will be absolute paths, and based on the Folder Path provided (i.e. if a UNC path is specified, all returned paths will be UNC paths).
The Folder Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Folder Path exceeds the system-defined maximum length (typically 32,767 characters).
The Folder Path is invalid (for example, it is on an unmapped drive).
The user the flow is executing as does not have the required permissions to get the paths of files or folders in the Folder Path, or any of its subfolders if Recursive is true.
An unexpected error occurs when getting the paths of files or folders in the Folder Path, or any of its subfolders if Recursive is true.
Thrown when using Search Options is either SearchOptions.Regex or SearchOptions.PatternMatching and the execution time of the search exceeds 30 seconds.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Path needs escaping
Folder Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the Folder Path (e.g. @"C:\Source").
Null or empty Search Pattern
A null or empty (i.e. "") Search Pattern means match any name; all additional block options such as Content Options etc. still take effect.
Comparison Types
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Handling of Exceptions
If an exception occurs when trying to match a file or folder name, it will be recorded and the block will continue processing the remaining files or folders. Once all files or folders are processed, recorded exceptions will be thrown within an OperationFailedException.
Known Limitations
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
6.3.7.10 - Get Folder Information
Get information about a folder (i.e. folder attributes, created, accessed and modified dates etc.).
6.3.7.10.1 - Get Folder Information
Gets information about a folder (e.g. folder attributes, created, accessed, modified dates etc.) at the specified folder path.
The Folder Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Folder Path exceeds the system-defined maximum length (typically 32,767 characters).
The Folder Path is invalid (for example, it is on an unmapped drive).
The user the flow is executing as does not have the required permissions to get information about the folder at the Folder Path.
An unexpected error occurs when getting information for the folder at the Folder Path or any of its content.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Path needs escaping
Folder Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the Folder Path (e.g. @"C:\Source").
6.3.7.11 - Move File(s)
Move a file or multiple files.
6.3.7.11.1 - Move File
Moves a file at the specified file path to the given destination path.
Move a file to a folder keeping the same file name
This example will move "C:\Source\OriginalFile.txt" to "C:\Destination", with the same file name of "OriginalFile.txt".
In this example assume "C:\Destination" does not already contain a file named "OriginalFile.txt", so overwrite can be set to either true or false and it will still work.
This example will move "C:\Source\OriginalFile.txt" to "C:\Destination", with a new file name of "NewFile.txt".
To rename the file when it is being moved, please note that the Destination Path must be a file path, rather than a folder path (e.g. "C:\Destination\NewFile.txt" rather than "C:\Destination").
In this example assume "C:\Destination" does not already contain a file named "NewFile.txt", so overwrite can be set to either true or false and it will still work.
Move a file to a folder overwriting any file that already exists with the same name
This example will move "C:\Source\FileAlreadyExists.txt" to "C:\Destination", with the same file name of "FileAlreadyExists.txt".
In this example assume "C:\Destination" already contains a file named "FileAlreadyExists.txt", so overwrite must be set to true to ensure the content of the existing file can be overwritten.
If it points to a folder, the moved file will have the name specified in the File Path.
If it points to a file, the moved file will have the name specified in the Destination Path.
Any non-existing folders within the Destination Path will be automatically created.
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
If the file exists, Overwrite must be set to true, otherwise an OperationFailedException will be thrown. By default, this is set to false to avoid implicit and accidental overwriting of existing files.
The Destination Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The Destination Path (if it points to a file), or the Destination Path (if it points to a folder) plus the file name, exceeds the system-defined maximum length (typically 32,767 characters).
The File Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The File Path exceeds the system-defined maximum length (typically 32,767 characters).
The file in the specified Destination Path exists and overwrite is false.
The file in the specified Destination Path exists, is read-only and overwrite is true.
The user the flow is executing as does not have the required permissions to move the file (e.g. not having read access to the File Path or write access to the Destination Path).
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Path and Destination Path need escaping
File Path and Destination Path require \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\OriginalFile.txt"), or
Prepending an @ character before the start of the File Path (e.g. @"C:\Source\OriginalFile.txt") and Destination Path (e.g. @"C:\Destination").
File Attributes
When moving a file from the File Path to the new Destination Path, all of the file’s attributes will also be moved.
For information about the file attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
6.3.7.11.2 - Move Files
Moves files at the specified file paths to the given destination path.
Move files to a folder keeping the same file names
This example will move ["C:\Source\OriginalFile1.txt", "C:\Source\OriginalFile2.txt"] to "C:\Destination", with the same file names of "OriginalFile1.txt" and "OriginalFile2.txt".
In this example assume "C:\Destination" does not already contain a file named "OriginalFile1.txt" or a file named "OriginalFile2.txt", so overwrite can be set to either true or false and it will still work.
Moving ["C:\Source\OriginalFile1.txt", "C:\Source\OriginalFile2.txt"] to "C:\Destination" that does not already contain files named "OriginalFile1.txt" and "OriginalFile2.txt" will:
Move "C:\Source\OriginalFile1.txt" to "C:\Destination\OriginalFile1.txt" with:
Move files to a folder overwriting any files that already exists with the same names
This example will move ["C:\Source\FileAlreadyExists1.txt", "C:\Source\FileAlreadyExists2.txt"] to "C:\Destination", with the same file names of "FileAlreadyExists1.txt" and "FileAlreadyExists2.txt".
In this example assume "C:\Destination" already contains a file named "FileAlreadyExists1.txt" and a file named "FileAlreadyExists2.txt", so overwrite must be set to true to ensure the content of the existing files can be overwritten.
Moving ["C:\Source\FileAlreadyExists1.txt", "C:\Source\FileAlreadyExists2.txt"] to "C:\Destination" and overwriting the existing files named "FileAlreadyExists1.txt" and "FileAlreadyExists2.txt" will:
Overwrite the existing file at "C:\Destination\FileAlreadyExists1.txt" with:
The content copied from "C:\Source\FileAlreadyExists1.txt".
The Date Created copied from "C:\Source\FileAlreadyExists1.txt".
The Date Accessed copied from "C:\Source\FileAlreadyExists1.txt"
The Date Modified copied from "C:\Source\FileAlreadyExists1.txt".
The File Attributes copied from "C:\Source\FileAlreadyExists1.txt".
Overwrite the existing file at "C:\Destination\FileAlreadyExists2.txt" with:
The content copied from "C:\Source\FileAlreadyExists2.txt".
The Date Created copied from "C:\Source\FileAlreadyExists2.txt".
The Date Accessed copied from "C:\Source\FileAlreadyExists2.txt".
The Date Modified copied from "C:\Source\FileAlreadyExists2.txt".
The File Attributes copied from "C:\Source\FileAlreadyExists2.txt".
The moved files will have the names specified in the File Paths.
Any non-existing folders within the Destination Path will be automatically created.
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
If any file exists, Overwrite must be set to true, otherwise an OperationFailedException will be thrown. By default, this is set to false to avoid implicit and accidental overwriting of existing files.
The Destination Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The Destination Path (if it points to a file), or the Destination Path (if it points to a folder) plus the file name, exceeds the system-defined maximum length (typically 32,767 characters).
Any file path in File Paths contains leading spaces.
Any file path in File Paths contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
Any file path in File Paths exceeds the system-defined maximum length (typically 32,767 characters).
Any file path in File Paths exists in the specified Destination Path with the same name, is read-only and overwrite is true.
The user the flow is executing as does not have the required permissions to move any file (e.g. not having read access to a file path in File Paths or write access to the Destination Path).
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Paths and Destination Path need escaping
Each file path in File Paths and Destination Path require \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\OriginalFile.txt"), or
Prepending an @ character before the start of the
file path (e.g. @"C:\Source\OriginalFile.txt") and Destination Path (e.g. @"C:\Destination").
File Attributes
When moving a file in the File Paths to the new Destination Path, all of the file’s attributes will also be moved.
For information about the file attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
Handling of Exceptions
If an exception occurs when trying to move a file in the File Paths, it will be recorded and the block will continue processing the remaining files. Once all files are processed, recorded exceptions will be thrown within an OperationFailedException.
6.3.7.12 - Move Folder(s)
Move a folder or folders.
6.3.7.12.1 - Move Folder
Moves a folder at the specified folder path to the given destination path.
Moving "C:\Source\Folder" and its content to "C:\Destination" with the Overwrite option set to true, and where "C:\Destination\Folder", "C:\Destination\Folder\SubFolderAlreadyExists" and "C:\Destination\Folder\FileAlreadyExists.txt" already exist will:
Overwrite the existing folder at "C:\Destination\Folder" with:
The Date Created left unchanged.
The Date Accessed set to the time the move occurred.
The Date Modified set to the time the move occurred.
Overwrite the existing file at "C:\Destination\Folder\FileAlreadyExists.txt" with:
The content copied from "C:\Source\Folder\FileAlreadyExists.txt".
The Date Created copied from "C:\Source\Folder\FileAlreadyExists.txt".
The Date Accessed copied from "C:\Source\Folder\FileAlreadyExists.txt".
The Date Modified copied from "C:\Source\Folder\FileAlreadyExists.txt".
The File attributes copied from "C:\Source\Folder\FileAlreadyExists.txt".
Move a folder’s content only
This example will move "C:\Source\Folder" content only to "C:\Destination".
In this example assume:
"C:\Source\Folder" contains:
An empty sub-folder named "SubFolder".
A file named "File.txt".
"C:\Destination" does not already contain a folder named "SubFolder" or a file named "File.txt", so overwrite can be set to either true or false and it will still work.
Moving "C:\Source\Folder" content only to "C:\Destination" with the Overwrite option set to true, and where "C:\Destination\SubFolderAlreadyExists" and "C:\Destination\FileAlreadyExists.txt" already exist will:
Move "C:\Source\Folder\SubFolder" to "C:\Destination\SubFolder" with:
Overwrite the existing file at "C:\Destination\FileAlreadyExists.txt" with:
The content copied from "C:\Source\Folder\FileAlreadyExists.txt".
The Date Created copied from "C:\Source\Folder\FileAlreadyExists.txt".
The Date Accessed copied from "C:\Source\Folder\FileAlreadyExists.txt".
The Date Modified copied from "C:\Source\Folder\FileAlreadyExists.txt".
The File attributes copied from "C:\Source\Folder\FileAlreadyExists.txt".
Move a folder and its content to the same location but with a different name
If it is required to move a folder and its content into the same folder it is currently located in, but with a different name, then it is not possible to do with this block; the Rename Folder block must be used instead.
Move a folder and its content to a different location but with a different name
If it is required to move a folder and its content into a different folder than the one it is currently located in, but with a different name, it is not possible to do with a single block; you must use a combination of this block and the Rename Folder block.
Properties
Folder Path
The Folder Path to move the folder and/or its content from.
The Folder Path is case-insensitive, cannot contain any wildcard characters, and any trailing spaces will be automatically removed.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, please see File & Folder Paths.
The moved folders and files will have the same names as the folders and files moved.
Any non-existing folders within the Destination Path will be automatically created.
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Option to Overwrite the folder and/or contents being moved to in the Destination Path if they already exist.
If the folder and/or contents exists, Overwrite must be set to true, otherwise an OperationFailedException will be thrown. By default, this is set to false to avoid implicit and accidental overwriting of existing folders and files.
The Destination Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Destination Path exceeds the system-defined maximum length (typically 32,767 characters).
The Folder Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Folder Path exceeds the system-defined maximum length (typically 32,767 characters).
Any file being moved already exists in the specified Destination Path and overwrite is false.
Any file being moved already exists in the specified Destination Path, is read-only and overwrite is true.
The user the flow is executing as does not have the required permissions to move the folder or any of its content (e.g. not having read access to the Folder Path or its content, or write access to the Destination Path).
The operation is cyclic (e.g. moving a folder into one of its sub-folders).
An unexpected error occurs when moving the folder or any of its content.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Path and Destination Path need escaping
Folder Path and Destination Path require \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the Folder Path (e.g. @"C:\Source") and Destination Path (e.g. @"C:\Destination").
Folder Attributes
When moving the folder at the specified Folder Path or any folder under it to the new Destination Path, if the folder already exists in the destination its attributes remain unchanged.
For information about the folder attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
File Attributes
When moving a file under Folder Path to the new Destination Path, all of the file’s attributes are also moved.
For information about the file attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
An option can also be specified to Overwrite anything being moved that already exists in the Destination Path.
Examples
Move folders and their content
This example will move ["C:\Source\Folder1", "C:\Source\Folder2"] and their content to "C:\Destination".
In this example assume:
"C:\Source\Folder1" contains:
An empty sub-folder named "SubFolder1".
A file named "File1.txt".
"C:\Source\Folder2" contains:
An empty sub-folder named "SubFolder2".
A file named "File2.txt".
"C:\Destination" does not already contain a folder named "Folder1" or "Folder2", so overwrite can be set to either true or false and it will still work.
Moving ["C:\Source\Folder1", "C:\Source\Folder2"] and their content to "C:\Destination" that does not already contain folders named "Folder1" and "Folder2" will:
Move "C:\Source\Folder1" to "C:\Destination\Folder1" with:
Moving ["C:\Source\Folder1", "C:\Source\Folder2"] and their content to "C:\Destination" with the Overwrite option set to true, and where "C:\Destination\Folder1", "C:\Destination\Folder1\SubFolderAlreadyExists1", "C:\Destination\Folder1\FileAlreadyExists1.txt", "C:\Destination\Folder2", "C:\Destination\Folder2\SubFolderAlreadyExists2" and "C:\Destination\Folder2\FileAlreadyExists2.txt" already exist will:
Overwrite the existing folder at "C:\Destination\Folder1" with:
The Date Created left unchanged.
The Date Accessed set to the time the move occurred.
The Date Modified set to the time the move occurred.
Overwrite the existing file at "C:\Destination\Folder2\FileAlreadyExists2.txt" with:
The content copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The Date Created copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The Date Accessed copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The Date Modified copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The File attributes copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
Move the folders’ content only
This example will move ["C:\Source\Folder1", "C:\Source\Folder2"] content only to "C:\Destination".
In this example assume:
"C:\Source\Folder1" contains:
An empty sub-folder named "SubFolder1".
A file named "File1.txt".
"C:\Source\Folder2" contains:
An empty sub-folder named "SubFolder2".
A file named "File2.txt".
"C:\Destination" does not already contain a folder named "SubFolder1" or "SubFolder2" or a file named "File1.txt" or "File2.txt", so overwrite can be set to either true or false and it will still work.
Moving ["C:\Source\Folder1", "C:\Source\Folder2"] content only to "C:\Destination" that does not already contain a folder named "SubFolder1" or "SubFolder2" or a file named "File1.txt" or "File2.txt" will:
Move "C:\Source\Folder1\SubFolder1" to "C:\Destination\SubFolder1" with:
Moving ["C:\Source\Folder1", "C:\Source\Folder2"] content only to "C:\Destination" with the Overwrite option set to true, and where "C:\Destination\SubFolderAlreadyExists1", "C:\Destination\SubFolderAlreadyExists2", "C:\Destination\FileAlreadyExists1.txt" and "C:\Destination\FileAlreadyExists2.txt" already exist will:
Move "C:\Source\Folder1\SubFolder1" to "C:\Destination\SubFolder1" with:
Overwrite the existing file at "C:\Destination\FileAlreadyExists2.txt" with:
The content copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The Date Created copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The Date Accessed copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The Date Modified copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
The File attributes copied from "C:\Source\Folder2\FileAlreadyExists2.txt".
Move folders and their content to the same location but with a different name
If it is required to move folders and their content into the same folder they are currently located in, but with a different name, then it is not possible to do with this block; the Rename Folder block must be used instead.
Move folders and their content to a different location but with a different name
If it is required to move folders and their content into a different folder than the one they are currently located in, but with a different name, it is not possible to do with a single block; you must use a combination of this block and the Rename Folder block.
Properties
Folder Paths
The Folder Paths to move the folders and/or their content from.
Each folder path in Folder Paths is case-insensitive, cannot contain any wildcard characters, and any trailing spaces will be automatically removed.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, please see File & Folder Paths.
The moved folders and files will have the same names as the folders and files copied.
Any non-existing folders within the Destination Path will be automatically created.
For information about the supported file and folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Option to Overwrite the folders and/or contents being moved to in the Destination Path if they already exist.
If any of the folders and/or contents exists, Overwrite must be set to true, otherwise an OperationFailedException will be thrown. By default, this is set to false to avoid implicit and accidental overwriting of existing folders and files.
The Destination Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Destination Path exceeds the system-defined maximum length (typically 32,767 characters).
Any folder path in Folder Paths contains leading spaces.
Any folder path in Folder Paths contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
Any folder path in Folder Paths exceeds the system-defined maximum length (typically 32,767 characters).
Any file being moved already exists in the specified Destination Path and overwrite is false.
Any file being moved already exists in the specified Destination Path, is read-only and overwrite is true.
The user the flow is executing as does not have the required permissions to move the folder or any of its content (e.g. not having read access to any of the folders in Folder Paths or its content, or write access to the Destination Path).
The operation is cyclic (e.g. moving a folder into one of its sub-folders).
An unexpected error occurs when moving a folder or any of its content.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Path and Destination Path need escaping
Each folder paths in Folder Paths and Destination Path require \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the folder path (e.g. @"C:\Source") and Destination Path (e.g. @"C:\Destination").
Folder Attributes
When moving the folders at the specified Folder Paths or any folder under them to the new Destination Path, if the folder already exists in the destination its attributes remain unchanged.
For information about the folder attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
File Attributes
When moving a file under any of the Folder Paths to the new Destination Path, all of the file’s attributes are also moved.
For information about the file attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
Conflicting Content
If two or more paths in the specified Folder Paths contain content (folders or files) with the same name, and Overwrite and Content Only are true:
The attributes of the folder/file in the Destination Path will be that of the first one moved.
For files, the content of the file in the Destination Path will be that of the last one moved.
Handling of Exceptions
If an exception occurs when trying to move a folder in Folder Paths, it will be recorded and the block will continue processing the remaining folders. Once all folders are processed, recorded exceptions will be thrown within an OperationFailedException.
6.3.7.13 - Read File
Read the content of a file.
6.3.7.13.1 - Read All Lines
Reads all lines from a file at the specified file path.
($)Lines is a variable that will be set to an IList<String>
Result
Reading all lines from "C:\Source\File.txt" results in the variable ($)Lines being updated to the following:
["This is Line 1","This is Line 2","This is Line 3","This is Line 4","This is Line 5","This is Line 6","This is Line 7","This is Line 8","This is Line 9","This is Line 10"]
Option to specify the Encoding that should be used to read the file.
Most of the time Encoding can be left as null; allowing the block to automatically attempt to detect the encoding of the file based on the presence of byte order marks. However, if it is found that the returned Lines are not in the correct format because the block was unable to detect the encoding of the file, it is possible to specify the Encoding explicitly using this property.
For information about encoding, examples of available encodings and using them, please see Encoding.
A line is defined as a sequence of characters followed by a carriage return (i.e. \r), a line feed (i.e. \n), or a carriage return immediately followed by a line feed. The resulting Lines do not contain the terminating carriage returns and/or line feeds.
The File Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The File Path exceeds the system-defined maximum length (typically 32,767 characters).
The File Path is invalid (for example, it is on an unmapped drive).
The user the flow is executing as does not have the required permissions to read the file.
For information about the supported file path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Path needs escaping
File Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\File.txt"), or
Prepending an @ character before the start of the File Path (e.g. @"C:\Source\File.txt").
Encoding of text
For information about encoding of text, examples of available encodings and using them, please see Encoding.
6.3.7.13.2 - Read All Text
Reads all text from a file at the specified file path.
($)Text is a variable that will be set to a String
Result
Reading all text from "C:\Source\File.txt" results in the variable ($)Text being updated to the following:
"This is Line 1
This is Line 2
This is Line 3
This is Line 4
This is Line 5
This is Line 6
This is Line 7
This is Line 8
This is Line 9
This is Line 10"
Option to specify the Encoding that should be used to read the file.
Most of the time Encoding can be left as null; allowing the block to automatically attempt to detect the encoding of the file based on the presence of byte order marks. However, if it is found that the returned Text are not in the correct format because the block was unable to detect the encoding of the file, it is possible to specify the Encoding explicitly using this property.
For information about encoding, examples of available encodings and using them, please see Encoding.
The File Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The File Path exceeds the system-defined maximum length (typically 32,767 characters).
The File Path is invalid (for example, it is on an unmapped drive).
The user the flow is executing as does not have the required permissions to read the file.
For information about the supported file path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Path needs escaping
File Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\File.txt"), or
Prepending an @ character before the start of the File Path (e.g. @"C:\Source\File.txt").
Encoding of text
For information about encoding of text, examples of available encodings and using them, please see Encoding.
6.3.7.14 - Rename Folder
Rename a folder.
6.3.7.14.1 - Rename Folder
Renames a folder at the specified folder path to a new name.
The Folder Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any folder names.
The Folder Path exceeds the system-defined maximum length (typically 32,767 characters).
The Folder Path is a win32 device path (i.e starts with a "\\.\").
The Folder Path is invalid (for example, it is on an unmapped drive).
The user the flow is executing as does not have the required permissions to rename the folder or any of its content (e.g. not having read access to the Folder Path or its content, or write access to the parent of Folder Path.
An unexpected error occurs when renaming the folder.
For information about the supported folder path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
Folder Path needs escaping
Folder Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\"), or
Prepending an @ character before the start of the Folder Path (e.g. @"C:\Source").
Folder Attributes
When renaming the folder at the specified Folder Path all of the folder’s attributes are left unchanged.
For information about the folder attributes (i.e. ReadOnly, Hidden, Archive etc.), please see File & Folder Attributes.
6.3.7.15 - Search File(s)
Search a file or multiple files.
6.3.7.15.1 - Search File
Searches a file at a specified file path for a matching search pattern.
Search Options can be specified to choose whether to use a ContainsText, PatternMatching or Regex search.
Encoding can be specified if needed to explicitly state the encoding that should be used to read and search the file.
A Comparison Type option can specified to choose how it is determined whether text matches the Search Pattern (e.g. whether the search is case-sensitive or case-insensitive).
Examples
Get matches for a given text
This example will get all matches in the file "C:\Source\File.txt" that match the text "error".
It will perform a case-insensitive search, and let the block determine the encoding of the file automatically.
In this example assume "C:\Source\File.txt" contains the following text:
Error: Failed to determine uptime.
Information: Uptime is 2 hours.
Information: Uptime is 3 hours.
Error: An terminal error has occurred. The service will restart now.
This example will get all matches in the file "C:\Source\File.txt" that match the pattern "Uptime is * hours.".
It will perform a case-sensitive search, and let the block determine the encoding of the file automatically.
In this example assume "C:\Source\File.txt" contains the following text:
Error: Failed to determine uptime.
Information: Uptime is 2 hours.
Information: Uptime is 3 hours.
Error: An terminal error has occurred. The service will restart now.
($)Matches is a variable that will be set to an IList<FileMatch> value
Result
Searching "C:\Source\File.txt" for all text matching the pattern "Uptime is * hours." (case-sensitive), results in the variable ($)Matches being updated to the following:
[{"FilePath":"C:\\Source\\File.txt","Line":2,"Value":"Uptime is 2 hours.","Index":13,"Length":18,"Groups":{}},{"FilePath":"C:\\Source\\File.txt","Line":3,"Value":"Uptime is 3 hours.","Index":13,"Length":18,"Groups":{}}]
Get matches for a given regex
This example will get all matches in the file "C:\Source\File.txt" that match the regex "^Error:.*$".
It will perform a case-sensitive search, explicitly specify the encoding of the file as UTF-8 and will match any line that starts with "Error:".
In this example assume "C:\Source\File.txt" contains the following text:
Error: Failed to determine uptime.
Information: Uptime is 2 hours.
Information: Uptime is 3 hours.
Error: An terminal error has occurred. The service will restart now.
($)Matches is a variable that will be set to an IList<FileMatch> value
Result
Searching "C:\Source\File.txt" for all text matching the regex "^Error:.*$" (case-sensitive), results in the variable ($)Matches being updated to the following:
[{"FilePath":"C:\\Source\\File.txt","Line":1,"Value":"Error: Failed to determine uptime.","Index":0,"Length":34,"Groups":{}},{"FilePath":"C:\\Source\\File.txt","Line":4,"Value":"Error: An terminal error has occurred. The service will restart now.","Index":0,"Length":68,"Groups":{}}]
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
Option to specify the Encoding that should be used to read and search the file.
Most of the time Encoding can be left as null; allowing the block to automatically attempt to detect the encoding of the file based on the presence of byte order marks. However, if it is found that the returned Matches are not correct because the block was unable to detect the encoding of the file, it is possible to specify the Encoding explicitly using this property.
For information about encoding, examples of available encodings and using them, please see Encoding.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
The File Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The File Path exceeds the system-defined maximum length (typically 32,767 characters).
The File Path is invalid (for example, it is on an unmapped drive).
The user the flow is executing as does not have the required permissions to search the File Path.
An unexpected error occurs when searching the File Path.
Thrown when using Search Options is either SearchOptions.Regex or SearchOptions.PatternMatching and the execution time of the search exceeds 30 seconds.
For information about the supported file path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Path needs escaping
File Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\File.txt"), or
Prepending an @ character before the start of the File Path (e.g. @"C:\Source\File.txt").
Null or empty Search Pattern
A null or empty (i.e. "") Search Pattern means match anything; all additional block options such as Search Options etc. still take effect.
Encoding of text
For information about encoding of text, examples of available encodings and using them, please see Encoding.
Comparison Types
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Known Limitations
The text in the file at the specified File Path is searched line-by-line. As a result, when using SearchOptions.Regex the in-line s regex character is not supported.
If the text in the file at the specified File Path ends with a blank line (0 length) that line will not be read and therefore not matched against.
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
6.3.7.15.2 - Search Files
Searches files at the specified file paths for a matching search pattern.
Search Options can be specified to choose whether to use a ContainsText, PatternMatching or Regex search.
Encoding can be specified if needed to explicitly state the encoding that should be used to read and search the files.
A Comparison Type option can specified to choose how it is determined whether text matches the Search Pattern (e.g. whether the search is case-sensitive or case-insensitive).
Examples
Get matches for a given text
This example will get all matches in the files ["C:\Source\File1.txt", "C:\Source\File2.txt"] that match the text "error".
It will perform a case-insensitive search, and let the block determine the encoding of the files automatically.
In this example assume "C:\Source\File1.txt" contains the following text:
Error: Failed to determine uptime.
Information: Uptime is 2 hours.
Information: Uptime is 3 hours.
Error: An terminal error has occurred. The service will restart now.
and "C:\Source\File2.txt" contains the following text:
Information: Uptime is 1 hour.
Information: Uptime is 2 hours.
Information: Uptime is 3 hours.
Error: Failed to determine uptime.
Error: Failed to determine uptime.
Information: Uptime is 6 hours.
This example will get all matches in the files ["C:\Source\File1.txt", "C:\Source\File2.txt"] that match the pattern "Uptime is * hour?.".
It will perform a case-sensitive search, and let the block determine the encoding of the files automatically.
In this example assume "C:\Source\File1.txt" contains the following text:
Error: Failed to determine uptime.
Information: Uptime is 2 hours.
Information: Uptime is 3 hours.
Error: An terminal error has occurred. The service will restart now.
and "C:\Source\File2.txt" contains the following text:
Information: Uptime is 1 hour.
Information: Uptime is 2 hours.
Information: Uptime is 3 hours.
Error: Failed to determine uptime.
Error: Failed to determine uptime.
Information: Uptime is 6 hours.
Searching the files ["C:\Source\File1.txt", "C:\Source\File2.txt"] for all text matching the pattern "Uptime is * hour?." (case-sensitive), results in the variable ($)Matches being updated to the following:
{"C:\\Source\\File1.txt":[{"FilePath":"C:\\Source\\File1.txt","Line":2,"Value":"Uptime is 2 hours.","Index":13,"Length":18,"Groups":{}},{"FilePath":"C:\\Source\\File1.txt","Line":3,"Value":"Uptime is 3 hours.","Index":13,"Length":18,"Groups":{}}],"C:\\Source\\File2.txt":[{"FilePath":"C:\\Source\\File2.txt","Line":1,"Value":"Uptime is 1 hour.","Index":13,"Length":17,"Groups":{}},{"FilePath":"C:\\Source\\File2.txt","Line":2,"Value":"Uptime is 2 hours.","Index":13,"Length":18,"Groups":{}},{"FilePath":"C:\\Source\\File2.txt","Line":3,"Value":"Uptime is 3 hours.","Index":13,"Length":18,"Groups":{}},{"FilePath":"C:\\Source\\File2.txt","Line":6,"Value":"Uptime is 6 hours.","Index":13,"Length":18,"Groups":{}}]}
Get matches for a given regex
This example will get all matches in the files ["C:\Source\File1.txt", "C:\Source\File2.txt"] that match the regex "^Error:.*$".
It will perform a case-sensitive search, explicitly specify the encoding of the files as UTF-8 and will match any lines that start with "Error:".
In this example assume "C:\Source\File1.txt" contains the following text:
Error: Failed to determine uptime.
Information: Uptime is 2 hours.
Information: Uptime is 3 hours.
Error: An terminal error has occurred. The service will restart now.
and "C:\Source\File2.txt" contains the following text:
Information: Uptime is 1 hour.
Information: Uptime is 2 hours.
Information: Uptime is 3 hours.
Error: Failed to determine uptime.
Error: Failed to determine uptime.
Information: Uptime is 6 hours.
Searching the files ["C:\Source\File1.txt", "C:\Source\File2.txt"] for all text matching the regex "^Error:.*$" (case-sensitive), results in the variable ($)Matches being updated to the following:
{"C:\\Source\\File1.txt":[{"FilePath":"C:\\Source\\File1.txt","Line":1,"Value":"Error: Failed to determine uptime.","Index":0,"Length":34,"Groups":{}},{"FilePath":"C:\\Source\\File1.txt","Line":4,"Value":"Error: An terminal error has occurred. The service will restart now.","Index":0,"Length":68,"Groups":{}}],"C:\\Source\\File2.txt":[{"FilePath":"C:\\Source\\File2.txt","Line":4,"Value":"Error: Failed to determine uptime.","Index":0,"Length":34,"Groups":{}},{"FilePath":"C:\\Source\\File2.txt","Line":5,"Value":"Error: Failed to determine uptime.","Index":0,"Length":34,"Groups":{}}]}
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
Option to specify the Encoding that should be used to read and search the files.
Most of the time Encoding can be left as null; allowing the block to automatically attempt to detect the encoding of the files based on the presence of byte order marks. However, if it is found that the returned Matches are not correct because the block was unable to detect the encoding of the files, it is possible to specify the Encoding explicitly using this property.
For information about encoding, examples of available encodings and using them, please see Encoding.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
The key of each entry is the file path, and the value contains a FileMatch for every text in the file path that matches the specified Search Pattern based on the other specified options.
A basic example with a single file path and a single FileMatch can be seen below:
{"C:\\Source\\File1.txt":[{"FilePath":"C:\\Source\\File1.txt","Line":1,"Value":"Error: Failed to determine uptime.","Index":0,"Length":34,"Groups":{}}]}
For more information see the example above, or the FileMatch data type.
Any file path in File Paths contains leading spaces.
Any file path in File Paths contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
Any file path in File Paths exceeds the system-defined maximum length (typically 32,767 characters).
Any file path in File Paths is invalid (for example, it is on an unmapped drive).
The user the flow is executing as does not have the required permissions to search a file path in File Paths.
An unexpected error occurs when searching any file path in File Paths.
Thrown when using Search Options is either SearchOptions.Regex or SearchOptions.PatternMatching and the execution time of the search exceeds 30 seconds.
For information about the supported file path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Paths needs escaping
Each file path in File Paths requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\File.txt"), or
Prepending an @ character before the start of the File Paths (e.g. @"C:\Source\File.txt").
Null or empty Search Pattern
A null or empty (i.e. "") Search Pattern means match anything; all additional block options such as Search Options etc. still take effect.
Encoding of text
For information about encoding of text, examples of available encodings and using them, please see Encoding.
Comparison Types
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Handling of Exceptions
If an exception occurs when trying to search a file in the File Paths, it will be recorded and the block will continue processing the remaining files. Once all files are processed, recorded exceptions will be thrown within an OperationFailedException.
Known Limitations
The text in the files at the specified File Paths is searched line-by-line. As a result, when using SearchOptions.Regex the in-line s regex character is not supported.
If the text in the files at the specified File Paths ends with a blank line (0 length) that line will not be read and therefore not matched against.
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
6.3.7.16 - Write File
Write the content of a file.
6.3.7.16.1 - Write All Lines
Writes all specified lines to a file at the given file path.
Writes all specified Lines to the end of the file at the given File Path, with an option to explicitly specify the Encoding to write the file as if needed.
An option can also be specified to Overwrite rather than append to the file.
Examples
Write all lines, appending to the end of the file
This example will append ["New Line 1", "New Line 2"] to "C:\Source\File.txt", using UTF-8 encoding without a byte order mark.
In this example assume "C:\Source\File.txt" contains 2 lines:
The File Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The File Path exceeds the system-defined maximum length (typically 32,767 characters).
The File Path is invalid (for example, it is on an unmapped drive).
The file at the specified File Path is hidden or is a System file, and overwrite is true.
The file at the specified File Path is a read-only file.
The user the flow is executing as does not have the required permissions to write to the file.
For information about the supported file path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Path needs escaping
File Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\File.txt"), or
Prepending an @ character before the start of the File Path (e.g. @"C:\Source\File.txt").
Encoding of text
For information about encoding of text, examples of available encodings and using them, please see Encoding.
6.3.7.16.2 - Write All Text
Writes all specified text to a file at the given file path.
Writes all specified Text to the end of the file at the given File Path, with an option to explicitly specify the Encoding to write the file as if needed.
An option can also be specified to Overwrite rather than append to the file.
Examples
Write all text, appending to the end of the file
This example will append "New Line 1\r\nNew Line 2" to "C:\Source\File.txt", using UTF-8 encoding without a byte order mark.
In this example assume "C:\Source\File.txt" contains the following text:
The File Path contains only whitespace, or the NUL character (i.e. \0), or contains one or more invalid characters (i.e. ", *, ?, |, <, >, :, \, /) in any file or folder names.
The File Path exceeds the system-defined maximum length (typically 32,767 characters).
The File Path is invalid (for example, it is on an unmapped drive).
The file at the specified File Path is hidden or is a System file, and overwrite is true.
The file at the specified File Path is a read-only file.
The user the flow is executing as does not have the required permissions to write to the file.
For information about the supported file path formats (i.e. absolute, relative, UNC etc.) and examples of each, including how it is determined if a path points to a folder or a file, please see File & Folder Paths.
File Path needs escaping
File Path requires \ characters to be escaped, otherwise each unescaped \ will be reported as an Invalid property value message when trying to debug the flow.
Escaping can be done in two ways:
Escaping the \ character with another \ character (e.g. "C:\\Source\\File.txt"), or
Prepending an @ character before the start of the File Path (e.g. @"C:\Source\File.txt").
Encoding of text
For information about encoding of text, examples of available encodings and using them, please see Encoding.
6.3.8 - Flows
Blocks related to executing Flows.
6.3.8.1 - End Flow
Blocks that indicate the end of a flow.
6.3.8.1.1 - End Flow
Indicates the end of a flow.
End Flow
(Cortex.Blocks.Flows.EndFlow.EndFlowBlock)
Description
Indicates the end of a flow; when a flow execution reaches this block, the execution is ended.
A flow can contain any number of these blocks, and they can be placed anywhere in a flow.
The block has no block specific properties, but it does have the Description property that is common to all blocks. This allows users to give each block a description; typically this will be left blank for this block.
A breakpoint can be added to this block when debugging.
Examples
No examples for the block.
Properties
No properties for the block, other than the Description property that is common to all blocks.
Exceptions
No exceptions are thrown by the block.
Remarks
No remarks for the block.
6.3.8.2 - Run Flow
Blocks that are used to run another flow.
6.3.8.2.1 - Run Flow
Runs a chosen Flow, returning any output variables.
This example will run the Flowsquare-number-flow saving the output variables to ($)Outputs.
The Flowsquare-number-flow takes an Input Variable($)NumberToSquare, which is then multiplied by itself and saved to the Output Variable($)SquaredNumber. If no value is given for ($)NumberToSquare the default value 10 is used. The flow contains a block that checks that the Input Variable($)NumberToSquare is larger than 0, an exception is thrown by square-number-flow if ($)NumberToSquare is not larger than 0.
5 is passed into the Input Variable($)NumberToSquare for the Flowsquare-number-flow, which results in 25 being saved to the Output Variable($)SquaredNumber. This results in the variable ($)Outputs being updated to the following:
{"SquaredNumber":25}
Running a Flow with Default Input Variables
This example will run the Flowsquare-number-flow saving the output variables to ($)Outputs.
The Flowsquare-number-flow takes an Input Variable($)NumberToSquare, which is then multiplied by itself and saved to the Output Variable($)SquaredNumber. If no value is given for ($)NumberToSquare the default value 10 is used. The flow contains a block that checks that the Input Variable($)NumberToSquare is larger than 0, an exception is thrown by square-number-flow if ($)NumberToSquare is not larger than 0.
As no value is passed into the Input Variable($)NumberToSquare for the Flowsquare-number-flow the default of 10 is used, which results in 100 being saved to the Output Variable($)SquaredNumber. This results in the variable ($)Outputs being updated to the following:
This example will run the Flowsquare-number-flow saving the output variables to ($)Outputs.
The Flowsquare-number-flow takes an Input Variable($)NumberToSquare, which is then multiplied by itself and saved to the Output Variable($)SquaredNumber. If no value is given for ($)NumberToSquare the default value 10 is used. The flow contains a block that checks that the Input Variable($)NumberToSquare is larger than 0, an exception is thrown by square-number-flow if ($)NumberToSquare is not larger than 0.
The Flowsquare-number-flow contains a block that checks that the Input Variable($)NumberToSquare is larger than 0; if this is not the case an exception is thrown.
In this example, as -1 is passed into the Input Variable($)NumberToSquare and is not greater than 0, ($)Outputs is not updated and an exception is thrown. For more information on how the exception is thrown and how to handle the exception see Exceptions Thrown by a Child Flow.
It is recommended to use the Literal Editor for this property as it detects and warns of changes to the Flow Contract, allowing users to Sync the Editor.
A flow can be selected using the Literal Editor on the Flow Property, a list of all available flows will be presented to the developer and can be searched by the Name or Id of a flow.
Also, if an Input Variable has a default value, and the corresponding value in the Inputs Property is not of the same type, a Validation Error will be raised when the flow is validated.
Syncing the Inputs Property with the Flow Contract
When a flow is first selected the Inputs Property will be synced with the Flow Contract.
When the contract of the flow changes (e.g. Input Variables of a called Flow are updated), a prompt will appear when the block is selected, allowing the user to sync the editor.
Undoing this action will cause the Inputs Property to return to its previous state, from before it was synced, allowing any data to be retrieved from any extra Input Variables.
Known Limitations
The Flow Property can only use the Literal Editor
The Literal Editor is the only editor available for the Flow Property
In future this limitation may be removed.
Syncing the Inputs Property with the Flow Contract is not available when using editors other than the Literal Editor
This is always the first block in a flow. It cannot be deleted, and a flow can only contain one of these blocks.
The block has no block specific properties, but it does have the Description property that is common to all blocks. This allows users to give each block a description; typically this will be left blank for this block.
A breakpoint can be added to this block when debugging.
Examples
No examples for the block.
Properties
No properties for the block, other than the Description property that is common to all blocks.
An additional Settings option can be specified to control how the conversion should deal with things such as:
null objects
Date Time formats and offsets
Number formats
Text escaping
Type information
For information about the default Settings used if none are specified, as well as all other options that can be configured, please see JsonSerializerSettings.
Examples
Convert Json to a List (without Type information)
This example will convert "[[1, 2, 3], [4, 5, 6]]" into a List<Object>.
($)Object is a variable that will be set to a dynamic value (i.e. in this example to a List<Object>).
Result
Converting "[[1, 2, 3], [4, 5, 6]]" to an object results in the variable ($)Object being updated to the following:
[[1,2,3],[4,5,6]]
As the Json does not include any type information, ($)Object will be a List<Object>, rather than a List<List<Int32>>. This is because when performing the conversion there is no type information to tell the converter that the items in the list are List<Int32> data types.
Realistically, this example is only useful if you have already produced Json including type information by using the Convert Object To Json block. If this is the case, you can then convert it back with the correct data types.
During the conversion it will be attempted to convert the Json to the correct data type where possible. If the correct data type cannot be determined, then collection data types will be converted to a List<dynamic>, and other objects will be converted to a Structure.
Optional Settings that can be specified to control how the conversion should deal with things such as:
null objects
Date Time formats and offsets
Number formats
Text escaping
For information about the default Settings used if none are specified, as well as all other options that can be configured, please see JsonSerializerSettings.
If Json is set to the text "null", Object will be set to null.
Round-tripping
For most data types it should be possible to pass the Json created by a Convert Object To Json block to this block, and then pass the Object created by this block back to a Convert Object To Json block; this is called round-tripping.
It should be noted however, that not all data types will be able to be round-tripped.
An example of a data type that is not able to be round-tripped is HttpRequestHeaders. As it does not contain a public constructor it will not be able to be converted from its Json representation back into an HttpRequestHeaders; instead a JsonSerializationException will be thrown with a message like: "Cannot create and populate list type System.Net.Http.Headers.HttpRequestHeaders".
An additional Settings option can be specified to control how the conversion should deal with things such as:
null objects
Date Time formats and offsets
Number formats
Text escaping
Type information
For information about the default Settings used if none are specified, as well as all other options that can be configured, please see JsonSerializerSettings.
Examples
Convert a List to Json (without Type information)
This example will convert [[1, 2, 3], [4, 5, 6]] to its Json representation, without including type information.
($)Json is a variable that will be set to a String value.
Result
Converting [[1, 2, 3], [4, 5, 6]] to Json results in the variable ($)Json being updated to the following:
"[[1, 2, 3],[4, 5, 6]]"
As the resultant Json does not include any type information, if this Json was then used as input to the Convert Json To Object block, the resultant object would be a List<Object>, rather than a List<List<Int32>>.
($)Json is a variable that will be set to a String value.
Result
Converting [[1, 2, 3], [4, 5, 6]] to its Json representation (including type information) results in the variable ($)Json being updated to the following:
Optional Settings that can be specified to control how the conversion should deal with things such as:
null objects
Date Time formats and offsets
Number formats
Text escaping
For information about the default Settings used if none are specified, as well as all other options that can be configured, please see JsonSerializerSettings.
If Object is set to an empty List, Json is set to the text "[]".
Null Object
If Object is set to null, Json will be set to the text "null".
Round-tripping
For most data types it should be possible to pass the Json created by this block to the Convert Json To Object block, and then pass the Object created by the Convert Json To Object block back to this block; this is called round-tripping.
It should be noted however, that not all data types will be able to be round-tripped.
An example of a data type that is not able to be round-tripped is HttpRequestHeaders. As it does not contain a public constructor it will not be able to be converted from its Json representation back into an HttpRequestHeaders; instead a JsonSerializationException will be thrown with a message like: "Cannot create and populate list type System.Net.Http.Headers.HttpRequestHeaders".
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
Thrown when Index is out of the range of the list indexes. Valid indexes are between and including 0 and the count of items in the List.
Remarks
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
If Items is empty (i.e. []) there is nothing to add, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
If Items is empty (i.e. []) there is nothing to add, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
Thrown when Index is out of the range of the list indexes. Valid indexes are between and including 0 and the count of items in the List.
Remarks
Empty Items
If Items is empty (i.e. []) there is nothing to add, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.2 - Contains Item(s)
Check if an item or multiple items are contained in a list.
6.3.12.2.1 - Contains Item With Value
Checks if a List contains at least one item matching the specified value.
For information and examples of how it is determined whether an item matches a specified value, please see Object Equality.
Empty List
If List is empty (i.e. []), the variable specified in the Contains Item property is set to false.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.2.2 - Contains Items With Values
Checks if a List contains at least one item matching each of the specified values.
($)ContainsItems is a variable that will be set to a Boolean value
Result
[1, 2, 3, 3, 2, 1] contains at least one item matching each of the values in [1, 2, 3]; it contains two items with the value 1, two items with the value 2 and two items with the value 3. Therefore, the variable ($)ContainsItems will be updated to the following:
true
List does not contain items with Values
This example will check whether [1, 2, 3, 3, 2, 1] contains at least one item matching each of the values in [1, 2, 3, 10].
($)ContainsItems is a variable that will be set to a Boolean value
Result
[1, 2, 3, 3, 2, 1] does not contain at least one item matching each of the values in [1, 2, 3, 10]; it contains two items with the value 1, two items with the value 2 and two items with the value 3, but no items with the value 10. Therefore, the variable ($)ContainsItems will be updated to the following:
false
Properties
List
The List to check whether it contains at least one item matching each of the specified Values.
Items are considered matching if they have a value matching one of the specified Values.
If List contains at least one item matching each of the specified Values, the specified variable will be set to true, otherwise it will be set to false.
For information and examples of how it is determined whether an item matches a specified value, please see Object Equality.
Empty List
If List is empty (i.e. []), the variable specified in the Contains Items property is set to false.
Empty Values
If Values is empty (i.e. []), the variable specified in the Contains Items property is set to false.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
If List is empty (i.e. []), the variable specified in the Count property is set to 0.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.3.2 - Get Count Of Items With Value
Gets the count of items in a List with the specified value.
For information and examples of how it is determined whether an item matches a specified value, please see Object Equality.
Empty List
If List is empty (i.e. []), the variable specified in the Count property is set to 0.
No items matching Value
If List does not contain items matching the specified Value, the variable specified in the Count property is set to 0.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.3.3 - Get Counts Of Items With Values
Gets the counts of items in a List matching each of the specified values.
($)Counts is a variable that will be set to an IList<Int32> value
Result
Getting the counts of items in ["Some Text", 1] matching each of the values [1, 2, 3] results in the variable ($)Counts being updated to the following:
[1,0,0]
The counts of items matching each value are added to ($)Counts at the same index the value is in ($)Values. In this example, there is one item matching the first value 1, zero items matching the second value 2 and zero items matching the third value 3, resulting in ($)Counts being set to [1, 0, 0].
Properties
List
The List to get the Counts of items matching each of the specified Values for.
The Counts of items in List matching each of the specified Values.
For each value in Values, Counts will have a corresponding item whose value is the count of items in List matching the value.
I.e. The count of items matching the first value in Values will be saved as the first item in Counts; the count of items matching the second value in Values will be saved as the second item in Counts etc.
For information and examples of how it is determined whether an item matches a specified value, please see Object Equality.
Empty Values
If Values is empty (i.e. []), the variable specified in the Counts property is set to empty (i.e. []).
No items matching a specified value in Values
If List does not contain items matching one of the specified Values, 0 is written to the corresponding item in Counts for that value.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.4 - Get Index(es) of Items
Get the index of an item or indexes of multiple items contained in a list.
6.3.12.4.1 - Get Index Of Item With Value
Gets the index of the specified occurrence of an item in a List matching a value.
($)Index is a variable that will be set to an Int32 value
Result
An Occurrence of 1 means the first occurrence; 2 means second etc.
Attempting to get the index of the first occurrence of an item matching the value 1 from [1, 2, 3, 3, 2, 1] results in the variable ($)Index being updated to the following:
0
Get the Index of the last Occurrence of an item in a List matching a Value
This example will attempt to get the index of the last occurrence of an item matching the value 1 from [1, 2, 3, 3, 2, 1].
($)Index is a variable that will be set to an Int32 value
Result
An Occurrence of -1, means the last occurrence; -2 means second last etc.
Attempting to get the index of the last occurrence of an item matching the value 1 from [1, 2, 3, 3, 2, 1] results in the variable ($)List being updated to the following:
5
Properties
List
The List to get the Index of the specified Occurrence of matching item from.
Items are considered matching if they have the specified Value.
If List is empty (i.e. []), the variable specified in the Index property is set to -1.
No items matching Value, or Occurrence is not present
If List does not contain items matching the specified Value or the specified Occurrence is not present, the variable specified in the Index property is set to -1.
Occurrence is zero
If the Occurrence is set to 0, the variable specified in the Index property is set to -1.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.4.2 - Get Indexes Of Items With Value
Gets the indexes of all items in a List matching a value.
($)Indexes is a variable that will be set to an IList<Int32> value
Result
Attempting to get the indexes of all items matching the value 1 from [1, 2, 3, 3, 2, 1] results in the variable ($)Indexes being updated to the following:
[0,5]
Properties
List
The List to get the Indexes of matching items from.
Items are considered matching if they have the specified Value.
For information and examples of how it is determined whether an item matches a specified value, please see Object Equality.
Empty List
If List is empty (i.e. []), the variable specified in the Indexes property is set to [-1].
No items matching Value
If List does not contain items matching the specified Value, the variable specified in the Indexes property is set to [-1].
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
Thrown when Index is out of the range of the list indexes. Valid indexes are between and including 0 and the count of items in the List - 1.
Remarks
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
Thrown when Count is greater than the count of items in the List - 1.
Remarks
Negative Count
If Count is negative, Items contains all items in the List.
Zero Count
If Count is 0, Items is set to an empty list (i.e. []).
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
Thrown when Count is greater than the count of items in the List - 1.
Remarks
Negative Count
If Count is negative, Items contains all items in the List.
Zero Count
If Count is 0, Items is set to an empty list (i.e. []).
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.5.6 - Get Items At Index
Gets a count of items starting at the specified index of a List.
Thrown when Index is less than 0 or greater than the count of items in List - 1.
Thrown when Index + Count is greater than the count of items in the List - 1.
Remarks
Index is inclusive
The Index is an inclusive index, which means the item at the index will be included in Items.
Negative Count
If Count is negative, Items contains all items after and including the item at the specified Index in the List.
Zero Count
If Count is 0, Items is set to an empty list (i.e. []).
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.5.7 - Get Items At Indexes
Gets the items at each of the specified indexes of a List.
Thrown when any index in Indexes is less than 0 or greater than the count of items in List - 1.
Remarks
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
If List is empty (i.e. []) there is nothing to remove, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
Attempting to remove duplicate items from ["Some Text", 1] results in no operation, as there are no duplicates to remove. Therefore, the variable ($)List remains:
["Some Text",1]
Remove duplicate items from a List containing duplicates
This example will remove duplicate items from ["Some Text", 1, "Some Text", 1].
Removing duplicate items from ["Some Text", 1, "Some Text", 1] results in the second occurrences of "Some Text" and 1 being removed; with the variable ($)List being updated to the following:
If List is empty (i.e. []) there is nothing to remove, so no operation is performed.
List with no duplicates
If List does not contain duplicates there is nothing to remove, so no operation is performed.
Which duplicates are removed?
If List contains duplicates, the first occurrences of the duplicated items are kept; all other occurrences are removed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
If List is empty (i.e. []) there is nothing to remove, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
If List is empty (i.e. []) there is nothing to remove, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.6.5 - Remove Item At Index
Removes the item at the specified index of a List.
Thrown when Index is out of the range of the list indexes. Valid indexes are between and including 0 and the count of items in the List - 1.
Remarks
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.6.6 - Remove Item With Value
Removes the specified occurrence of an item matching a value from a List.
Attempting to remove the first occurrence of an item matching the value 1 from [] results in no operation, as there is nothing to remove. Therefore, the variable ($)List remains:
[]
Remove the first Occurrence of an item matching a Value from a List
This example will attempt to remove the first occurrence of an item matching the value 1 from [1, 2, 3, 3, 2, 1].
An Occurrence of 1 means remove the first occurrence; 2 means second etc.
Attempting to remove the first occurrence of an item matching the value 1 from [1, 2, 3, 3, 2, 1] results in the variable ($)List being updated to the following:
[2,3,3,2,1]
Remove the last Occurrence of an item matching a Value from a List
This example will attempt to remove the last occurrence of an item matching the value 1 from [1, 2, 3, 3, 2, 1].
An Occurrence of -1, means remove the last occurrence; -2 means second last etc.
Attempting to remove the last occurrence of an item matching the value 1 from [1, 2, 3, 3, 2, 1] results in the variable ($)List being updated to the following:
[1,2,3,3,2]
Properties
List
The List to remove the specified Occurrence of matching item from.
Items are considered matching if they have the specified Value.
List can be any IList<TItem>, where TItem represents the type of items that can be removed from the List.
If List is empty (i.e. []) there is nothing to remove, so no operation is performed.
No items matching Value, or Occurrence is not present
If List does not contain items matching the specified Value or the specified Occurrence is not present, there is nothing to remove, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.6.7 - Remove Items At Beginning
Removes a count of items from the beginning of a List.
Thrown when Count is greater than the count of items in the List - 1.
Remarks
Negative Count
If Count is negative all items in the List are removed.
Zero Count
If Count is 0 there is nothing to remove, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
Thrown when Count is greater than the count of items in the List - 1.
Remarks
Negative Count
If Count is negative all items in the List are removed.
Zero Count
If Count is 0 there is nothing to remove, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.6.9 - Remove Items At Index
Removes a count of items starting at the specified index of a List.
Thrown when Index is less than 0 or greater than the count of items in List - 1.
Thrown when Index + Count is greater than the count of items in the List - 1.
Remarks
Index is inclusive
The Index is an inclusive index, which means the item at the index will be included in the removed items.
Negative Count
If Count is negative all items after and including the specified Index in the List are removed.
Zero Count
If Count is 0 there is nothing to remove, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.6.10 - Remove Items At Indexes
Removes the items at each of the specified indexes of a List.
Thrown when any index in Indexes is less than 0 or greater than the count of items in List - 1.
Remarks
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
Attempting to remove all items matching the value 1 from [] results in no operation, as there is nothing to remove. Therefore, the variable ($)List remains:
[]
Remove all items matching a Value from a List
This example will attempt to remove all items matching the value 1 from [1, 2, 3, 3, 2, 1].
For information and examples of how it is determined whether an item matches a specified value, please see Object Equality.
Empty List
If List is empty (i.e. []) there is nothing to remove, so no operation is performed.
No items matching Value
If List does not contain items matching the specified Value, there is nothing to remove, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.6.12 - Remove Items With Values
Removes all items matching one of the specified values from a List.
Attempting to remove all items matching one of the values [1, 2] from [] results in no operation, as there is nothing to remove. Therefore, the variable ($)List remains:
[]
Remove all items matching one of the specified Values from a List
This example will attempt to remove all items matching one of the values [1, 2] from [1, 2, 3, 3, 2, 1].
Attempting to remove all items matching one of the values [1, 2] from [1, 2, 3, 3, 2, 1] results in the variable ($)List being updated to the following:
For information and examples of how it is determined whether an item matches a specified value, please see Object Equality.
Empty List
If List is empty (i.e. []) there is nothing to remove, so no operation is performed.
Empty Values
If Values is empty (i.e. []) there are no values to match, therefore nothing can be removed and no operation is performed.
No items matching a specified value in Values
If List does not contain items matching one of the specified Values, there is nothing to remove for that value.
No items matching Values
If List does not contain items matching any of the specified Values, there is nothing to remove, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.7 - Set Item(s)
Set an item or multiple items in a list to a new value.
If List is empty (i.e. []) there is nothing to set, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.7.2 - Set Item At Beginning
Sets the item at the beginning of a List to a new value.
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.7.3 - Set Item At End
Sets the item at the end of a List to a new value.
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.7.4 - Set Item At Index
Sets the item at the specified index of a List to a new value.
Thrown when Index is out of the range of the list indexes. Valid indexes are between and including 0 and the count of items in the List - 1.
Remarks
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.7.5 - Set Item With Value
Sets the specified occurrence of an item matching a value in a List to a new value.
An Occurrence of 1 means set the first occurrence; 2 means second etc.
Attempting to set the first occurrence of an item matching the value 1 in [1, 2, 3, 3, 2, 1] to 10 results in the variable ($)List being updated to the following:
[10,2,3,3,2,1]
Set the last Occurrence of an item matching a Value in a List to a New Value
This example will attempt to set the last occurrence of an item matching the value 1 in [1, 2, 3, 3, 2, 1] to 10.
An Occurrence of -1, means set the last occurrence; -2 means second last etc.
Attempting to set the last occurrence of an item matching the value 1 in [1, 2, 3, 3, 2, 1] to 10 results in the variable ($)List being updated to the following:
[1,2,3,3,2,10]
Properties
List
The List to set the specified Occurrence of matching item in.
Items are considered matching if they have the specified Value.
If List is empty (i.e. []) there is nothing to set, so no operation is performed.
No items matching Value, or Occurrence is not present
If List does not contain items matching the specified Value or the specified Occurrence is not present, there is nothing to set, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.7.6 - Set Items At Beginning
Sets the items at the beginning of a List to new values.
Setting the first and second items at the beginning of ["Some Text", 1, "Some More Text", 2] to ["Some Modified Text", 10] respectively, results in the variable ($)List being updated to the following:
The New Values to set the items at the beginning of List to.
The number of items in New Values determines the number of items that will be set at the beginning of List. One item means only the first item is set, two items means the first and second items are set etc.
The first item in List will be set to the first value in New Values; the second item in List will be set to the second value in New Values etc.
If New Values is empty (i.e. []) there is nothing to set, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.7.7 - Set Items At End
Sets the items at the end of a List to new values.
Setting the second last and last items at the end of ["Some Text", 1, "Some More Text", 2] to ["Some Modified Text", 10] respectively, results in the variable ($)List being updated to the following:
The number of items in New Values determines the number of items that will be set at the end of List. One item means only the last item is set, two items means the second last and last items are set etc.
The last item in List will be set to the last value in New Values; the second last item in List will be set to the second last value in New Values etc.
If New Values is empty (i.e. []) there is nothing to set, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.7.8 - Set Items At Index
Sets the items at the specified index of a List to new values.
Setting the two items at index 0 of ["Some Text", 1, "Some More Text", 2] to ["Some Modified Text", 10] respectively, results in the variable ($)List being updated to the following:
The number of items in New Values determines the number of items that will be set at the end of List. One item means one item is set, two items means two items are set etc.
The item at Index of List will be set to the first value in New Values; the item at Index + 1 of List will be set to the second value in New Values etc.
Thrown when Index is less than 0 or greater than the count of items in List - 1.
Thrown when Index + count of items in New Values is greater than the count of items in the List - 1.
Remarks
Index is inclusive
The Index is an inclusive index, which means the item at the index will be included in the set items.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.7.9 - Set Items At Indexes
Sets the items at each of the specified indexes of a List to new values.
Sets items at the first and third Indexes (i.e. [0, 2]) of a List to New Values
This example will set items at indexes 0 and 2 of ["Some Text", 1, "Some More Text", 2] to ["Some Modified Text", "Some More Modified Text"] respectively.
Setting items at indexes 0 and 2 of ["Some Text", 1, "Some More Text", 2] to ["Some Modified Text", "Some More Modified Text"] respectively, results in the variable ($)List being updated to the following:
["Some Modified Text",1,"Some More Modified Text",2]
The number of items in New Values must match the number of items in Indexes.
The List item at the first index in Indexes will be set to the first value in New Values; the List item at the second index in Indexes will be set to the second value in New Values etc.
Thrown when any index in Indexes is less than 0 or greater than the count of items in List - 1.
Remarks
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.7.10 - Set Items With Value
Sets all items matching a value in a List to a new value.
For information and examples of how it is determined whether an item matches a specified value, please see Object Equality.
Empty List
If List is empty (i.e. []) there is nothing to set, so no operation is performed.
No items matching Value
If List does not contain items matching the specified Value, there is nothing to set, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
6.3.12.7.11 - Set Items With Values
Sets all items matching one of the specified values in a List to new values.
Attempting to set all items matching one of the values [1, 2] in [1, 2, 3, 3, 2, 1] to [10, 20] respectively, results in the variable ($)List being updated to the following:
The number of items in New Values must match the number of items in Values.
List items matching the first value in Values will be set to the first value in New Values; List items matching the second value in Values will be set to the second value in New Values etc.
For information and examples of how it is determined whether an item matches a specified value, please see Object Equality.
Empty List
If List is empty (i.e. []) there is nothing to set, so no operation is performed.
No items matching a specified value in Values
If List does not contain items matching one of the specified Values, there is nothing to set for that value.
No items matching Values
If List does not contain items matching any of the specified Values, there is nothing to set, so no operation is performed.
Defining lists using literal syntax
For information about how to define lists using literal syntax, see Create a List<TItem>.
Defining lists using expression syntax
For information about how to define lists using expression syntax, see Create a List<TItem>.
Lists containing items of a single data type vs multiple data types
For information about the different types of lists, including those that can contain only a single type of item, and those that can contain multiple types of item, see Lists.
($)EventDetails, with value {"Process":{"Provision New User":{"Stages":[{"Configure Active Directory":{"Tasks":["Add User to Azure Active Directory","Add User to On-Premise Active Directory"]}},{"Configure Email":{"Tasks":["Create Outlook Account","Create Default Signature"]}}]}}}
{"@t":"2021-11-15T10:06:15.0000000Z","@mt":"{@Event}","Event":{"Type":"User Provisioning","Duration":{"StartedAt":"2021-11-15T10:05:32.0000000Z","EndedAt":"2021-11-15T10:06:12.0000000Z","InMs":40000,"$type":"EventDurationDetails"},"Details":{"Process":{"Provision New User":{"Stages":[{"Configure Active Directory":{"Tasks":["Add User to Azure Active Directory","Add User to On-Premise Active Directory"]}},{"Configure Email":{"Tasks":["Create Outlook Account","Create Default Signature"]}}]}},"Correlation":{"TraceId":null,"SpanId":null,"ParentSpanId":null,"$type":"EventCorrelationDetails"},"Service":{"Type":null,"IpAddressOrFqdn":null,"$type":"ServiceDetails"},"$type":"StructuredEventLog"}}}
For information about the format of the logs written, see Anatomy of a Log.
For information about where the logs are written to, see Configuring Logging.
Event Severity can be specified to define the severity of the event being logged.
Event Severity can be any of the following predefined values:
EventSeverity.Verbose - Logs that contain the most detailed messages. These messages may contain sensitive application data. These logs should never be enabled in a production environment.
EventSeverity.Debug - Logs that are used for interactive investigation during development. These logs should primarily contain information useful for debugging and have no long-term value.
EventSeverity.Information - Logs that track the general path of the flow execution. These logs should have long-term value.
EventSeverity.Warning - Logs that highlight an abnormal or unexpected event in the path of the flow execution, but do not otherwise cause the flow execution to exit.
EventSeverity.Error - Logs that highlight when the current flow execution exits due to an error. These should indicate a failure in the current flow execution, not a service-wide or process-wide failure.
EventSeverity.Fatal - Logs that describe an unrecoverable service or process error, or a catastrophic failure that requires immediate attention.
Event Severity can also be left blank or set to null, in which case it will default to EventSeverity.Information.
Logs with an Event Severity of EventSeverity.Information, have the event severity ommitted from the log that is written to the filesystem. This is to save disk space, as typically the highest volume of logs produced are Information logs. This cannot be changed and is a restriction of the underlying logging system used. All non-Information logs do include the event severity in the log that is written to the filesystem.
A list of the main log settings (highlighted above) and an accompanying description can be found below:
Log Setting
Default Value
Description
Default
"Verbose"
The default minimum log level that will be logged.Possible options are "Verbose", "Debug", "Information", "Warning", "Error", "Fatal".The order of log levels is "Verbose"->"Debug"->"Information"->"Warning"->"Error"->"Fatal". When setting the default log level, that level and every level to its right will be logged.
The location that logs will be written to.This value supports use of environment variables, as seen in the default value.If any part of the location does not exist, the logging will attempt to create it.The file names written will include a date format after the - and before .json (e.g. "LogEventBlock-yyyyMMdd.json" -> "LogEventBlock-20210921.json")The date format used will be decided by the value specified in rollingInterval.The file name may also include a file count number and is added automatically to make sure file names are unique. This can happen if rollOnFileSizeLimit is set to true and a log file reaches the size specified in fileSizeLimitBytes. It can also happen if the log file is locked by another process, preventing it from being written to.
rollingInterval
"Day"
The time interval at which the logging system will create and start logging to a new log file.Possible options are "Infinite", "Year", "Month", "Day", "Hour", "Minute".Infinite means that the log files never roll over based on a time interval.
fileSizeLimitBytes
50000000
The maximum file size in bytes that the loggging system will write to. Once this size is exceeded the logging system will create and start logging to a new log file.Null can be used to mean unlimited size.rollOnFileSizeLimit must be set to true for this setting to take effect.
rollOnFileSizeLimit
true
Whether the loggging system should start creating a new log file if the current one reaches the maximum file size specified in fileSizeLimitBytes.Possible options are true and false.
retainedFileCountLimit
365
The maximum number of files to retain on disk. Once this number is reached, the loggging system will start delete the oldest file.
Please note that if the appsetting.json file cannot be found for one of the services, the logger will use the same default settings specified above.
Anatomy of a Log
The format of the logs written by this block are the same as the logs written by the rest of the Cortex Services. This is to ensure logging is consistent and done one way within Cortex. Hopefully this will make it easier to work with logging, and also make it easier to gain a holistic picture into what has happened to a flow execution throughout its entire lifecycle (i.e. from initial request to returning the response to the caller), rather than just what happens inside of the flow.
An example log can be found below:
{"@t":"2021-11-15T10:06:15.0000000Z","@mt":"{@Event}","@l":"Debug","Event":{"Type":"User Provisioning","Duration":{"StartedAt":"2021-11-15T10:05:32.0000000Z","EndedAt":"2021-11-15T10:06:12.0000000Z","InMs":40000,"$type":"EventDurationDetails"},"Details":{"Process":{"Provision New User":{"Stages":[{"Configure Active Directory":{"Tasks":["Add User to Azure Active Directory","Add User to On-Premise Active Directory"]}},{"Configure Email":{"Tasks":["Create Outlook Account","Create Default Signature"]}}]}}},"Correlation":{"TraceId":null,"SpanId":null,"ParentSpanId":null,"$type":"EventCorrelationDetails"},"Service":{"Type":null,"IpAddressOrFqdn":null,"$type":"ServiceDetails"},"$type":"StructuredEventLog"}}}
A list of each of the log’s properties and an accompanying description can be found below:
Log Property
Description
@t
The date and time the log was written. The format is ISO 8601 Standard.
@mt
The message template for the log. This is set to log the entire Event.
@l
The level for the log. The value of Event Severity is used here.
Event
The event that was logged.
Event.Type
The type of event that was logged. This can be used for log analysis and reporting. The value of Event Type is used here.
Event.Duration
Contains the date and time the event started at, ended at, and its duration.
The date and time the event ended. The format is ISO 8601 Standard. The value of Ended At is used here.
Event.Duration.InMs
The duration of the event in milliseconds and is calculated using Event.Duration.StartedAt and Event.Duration.EndedAt .
Event.Duration.$type
The .Net data type used to represent the duration data. This can be ignored and is an artefact of the underlying implementation.
Event.Details
Contains the details of the event. The value of Event Details is written as a child property of this (e.g. in this example Event.Details.Process).
Event.Correlation
Contains details that can be used to correlate related events. E.g. The act of starting a new flow execution may result in multiple Cortex Services processing the event. As a result, each service may write its own logs, and additionally the flow developer may also write out multiple logs during the flow execution. The Correlation details allow all of these logs to easily be correlated back together when performing log analysis and reporting to gain a full picture of everything that happened.
Event.Correlation.TraceId
ID common to all related logs, so they can be easily correlated together.
Event.Correlation.SpanId
Unique ID for each log, so tools like Grafana can display a call stack, showing each step that occurred when processing an event.
Event.Correlation.ParentSpanId
The ID of the step that called this step of processing, so tools like Grafana can display a call stack, showing each step that occurred when processing an event.
Event.Correlation.$type
The .Net data type used to represent the correlation data. This can be ignored and is an artefact of the underlying implementation.
Event.Service
Contains details of the Cortex Service that logged this event, and will allow enhanced log analysis and reporting to gain a full picture of everything that happened.
Event.Service.Type
The type of the Cortex Service that logged this event.
Event.Service.IpAddressOrFqdn
The IP address or fully qualified domain name of the Cortex Service that logged this event.
Event.Service.$type
The .Net data type used to represent the service data. This can be ignored and is an artefact of the underlying implementation.
Event.$type
The .Net data type used to represent the event data. This can be ignored and is an artefact of the underlying implementation.
Null or Empty Event Type
If Event Type is left blank, null, or empty (i.e. "") it will default to Cortex.Blocks.Logs.LogEvent.LogEventBlock.
Null Event Severity
If Event Severity is left blank or set to null, it will default to EventSeverity.Information.
Null Started At
If Started At is left blank or set to null, a value of null will be logged.
Null Ended At
If Ended At is left blank or set to null, a value of null will be logged.
6.3.14 - Loops
Blocks used to perform looping.
6.3.14.1 - For Each Loop
Blocks used to loop through the items in a collection (i.e. Lists, Dictionaries and Structures).
6.3.14.1.1 - For Each Loop
Loops through all items in the specified collection (i.e. Lists, Dictionaries and Structures).
For Each Loop
(Cortex.Blocks.Loops.ForEach.ForEachLoopBlock)
Description
Loops through all items in the specified Collection (i.e. Lists, Dictionaries and Structures).
The "Index" and "Value" of the current item are returned as properties of a Structure, which is saved to the Current Iteration.
Examples
Loop through all items in a list
This example will loop through all items in ["Item1", "Item2", "Item3"].
($)CurrentIteration is a variable of type Structure
Result
Looping through all items in {"Key1": "Value1", "Key2": "Value2", "Key3": "Value3"} will result in 3 loops with ($)CurrentIteration being updated to the following:
Current Iteration is set to a Structure on each loop, containing the current item’s "Index" and "Value". "Index" is set to 0 on the first loop, and on each subsequent loop is incremented by 1.
Looping will continue whilst "Index" is less than the number of items in Collection, with the flow execution exiting via the block’s right port (blue loop icon).
Once "Index" equals the number of items in Collection, looping stops, the flow execution exits via the block’s bottom port (green tick) and Current Iteration is reset to an empty Structure.
If Current Iteration"Index" is modified during a loop, it will automatically be set back to its original value immediately before the next loop begins.
Current Index initially gets set to the value of Start Index on the first loop, and on each subsequent loop is incremented by the value of Increment.
If Increment is a positive value, the block will continue looping whilst Current Index is less than End Index; with the flow execution exiting via the block’s right port (blue loop icon).
If Increment is a negative value, the block will continue looping whilst Current Index is greater than Start Index; with the flow execution exiting via the block’s right port (blue loop icon).
When either of the above are not true the block stops looping, the flow execution exits via the block’s bottom port (green tick) and Current Index is reset to 0
At this moment, there is a known limitation with Current Index, which requires the variable used must have an Int32 value assigned to it before the block executes. If it does not then an InvalidPropertyValueException will be thrown the first time a flow execution executes this block.
For information about what an index is, please see Indexes.
The Start Index and End Index properties are both inclusive indexes, which means those indexes will be included in the looping range (e.g. if Start Index is 0 and End Index is 1, the block will loop 2 times).
The variable used for Current Index must have an Int32 value assigned to it before the block executes. If it does not then an InvalidPropertyValueException will be thrown the first time a flow execution executes this block.
Converts an object to text by replacing all {Property} format parameters in a specified format template with the Object’s corresponding property value.
It does this by replacing all {Property} format parameters in the specified Format Template with the corresponding property value from the given Object.
An additional Format Provider option can be specified to define the cultural rules used to control the formatting (e.g. new CultureInfo("en-US") will apply American English rules to the formatting).
"Your latest payment of {LastPaymentAmount:C2} has been received. You have paid {PercentagePaidOff:P0} of your total and have {TotalRemaining:C2} outstanding."
The format parameter {LastPaymentAmount:C2} will display the 99.99 as U.S currency to two decimal places (i.e. $99.99):
LastPaymentAmount - is replaced by the value of the "LastPaymentAmount" property (i.e. 99.99).
C - indicates to include the currency symbol for the specified culture (i.e. $).
2 - indicates to format the value to two decimal places.
The format parameter {PercentagePaidOff:P0} will display the 0.8000 as a percentage to zero decimal places (i.e. 80 %):
PercentagePaidOff - is replaced by the value of the "PercentagePaidOff" (i.e. 0.8000).
P - indicates the value should be formatted as a percentage.
0 - indicates to format the percentage value to zero decimal places.
The format parameter {TotalRemaining:C2} will display the 40 as U.S currency to two decimal places (i.e. $40.00):
TotalRemaining - is replaced by the value of the "TotalRemaining" property (i.e. 40).
C - indicates to include the currency symbol for the specified culture (i.e. $).
2 - indicates to format the value to two decimal places.
For information about format templates and parameters, please see Text Formatting.
($)Object, with value {"LastPaymentAmount":99.99, "PercentagePaidOff":0.8000, "PercentageRemaining":0.2000, "TotalPaidOff":350.99, "TotalRemaining":40}
($)FormatTemplate, with value "Your latest payment of {LastPaymentAmount:C2} has been received. You have paid {PercentagePaidOff:P0} of your total and have {TotalRemaining:C2} outstanding."
"Your latest payment of {LastPaymentAmount:C2} has been received. You have paid {PercentagePaidOff:P0} of your total and have {TotalRemaining:C2} outstanding."
results in the variable ($)Text being updated to the following:
"Your latest payment of $99.99 has been received. You have paid 80 % of your total and have $40.00 outstanding."
All {Property} format parameters which match a property name in the Object will be replaced by that property’s value.
The values of matching properties do not have to be text, they can be any data type. Any non-text value will be converted to its text representation when it is replaced.
For information about how types are converted to their text representation please see Converting Objects To Text.
Format Template can be specified to define the format of the resultant Text.
All {Property} format parameters in Format Template will be replaced with the corresponding property value from the Object.
{Property} format parameters are case-sensitive, so must exactly match the property name in the Object; those that do not will not be replaced.
If Format Template is specified but does not contain any {Property} format parameters, nothing is replaced; Text will be set to the value of Format Template.
Format Provider can be specified to define the cultural rules used to control the formatting (e.g. new CultureInfo("en-US") will apply American English rules to the formatting.).
If Format Provider is not specified or null, CultureInfo.InvariantCulture will be used; CultureInfo.InvariantCulture is associated with the English language but not with any country/region. For more information, please see Invariant Culture rules.
The formatted Text that results from replacing all {Property} format parameters in Format Template with their corresponding property value from the given Object.
Thrown when Format Template contains a format parameter that is invalid or not well-formed (e.g. "Cost is {TotalCost:Q2}, as "Q" is not a valid format parameter).
Please note that changes to operating system settings, could result in some of the examples above displaying different results.
For information about format templates and parameters, please see Text Formatting.
Null or Empty Format Template
If Format Template is specified but does not contain any {Property} format parameters, nothing is replaced; Text will be set to the value of Format Template.
If Format Provider is not specified or null, CultureInfo.InvariantCulture will be used; CultureInfo.InvariantCulture is associated with the English language but not with any country/region. For more information, please see Invariant Culture rules.
Nested Properties
Format parameters support nested properties, which means given an object like the following:
Any type of object can be copied, including Lists, Dictionaries, Structures etc.
A deep copy will be performed, which means if the Object contains other objects, they are also copied. This is as opposed to a shallow copy, which only makes a copy of the Object; in a shallow copy contained objects are not copied, they are left as the original.
Examples
Copy a List
This example will make a copy of [[1, 2, 3], [4, 5, 6]].
($)Copy is a variable that will be set to the type of the item (i.e. List<List<Int32>>)
Result
Making a copy of [[1, 2, 3], [4, 5, 6]] results in the variable ($)Copy being updated to the following:
[[1,2,3],[4,5,6]]
Note that ($)Copy is an exact copy. If ($)Copy has new items added to it, items updated in it, or items removed from it, the original that ($)Copy was copied from will not be affected.
Any type of object can be copied, including Lists, Dictionaries, Structures etc.
A deep copy will be performed, which means if the Object contains other objects, they are also copied. This is as opposed to a shallow copy, which only makes a copy of the Object; in a shallow copy contained objects are not copied, they are left as the original.
Duration can have positive and negative components where components are:
Years
Months
Days
Hours
Minutes
Seconds
Milliseconds
When waiting for Duration, the block will calculate the date time to wait until by adding the Duration to the current date time. It will first add years, followed by months, days, hours, minutes, seconds and finally milliseconds.
When adding months, if the current day component is greater than the last day in the resultant month, it will update the day to the last day for that month (e.g. adding one month onto 2021-01-31T23:59:59+00:00 will equate to 2021-02-28T23:59:59+00:00).
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Text To Add added in the correct place and re-assigns it to the variable specified in the Text property.
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Text To Add added in the correct place and re-assigns it to the variable specified in the Text property.
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Text To Add added in the correct place and re-assigns it to the variable specified in the Text property.
6.3.20.1.4 - Add Text Before Index
Adds text to another text before the specified index.
"A" is at index 0 in "ABCDEFGHIJKLMNOPQRSTUVWXYZ". Therefore, adding "|" before index 0 results in the variable ($)Text being updated to the following:
"|ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Add null or empty Text To Add to another Text before the given Index
This example will try to add null or "" before "A" (which is at index 0) in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Text To Add added in the correct place and re-assigns it to the variable specified in the Text property.
6.3.20.2 - Contains Text
Check if text is contained in another text.
6.3.20.2.1 - Contains All Text
Checks if text contains all of the texts in a given set of texts.
($)ContainsAllText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" contains all of the texts in ["The", "quick", "brown", "fox"]. Therefore, the variable ($)ContainsAllText will be updated to the following:
true
Text does not contain all of the texts in Texts To Find
This example will check whether "The quick brown fox jumps over the lazy dog" contains all of the texts in ["the", "slow", "brown", "fox"].
($)ContainsAllText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" does not contain all of the texts in ["the", "slow", "brown", "fox"]; "slow" is missing, and "the" does not match "The" as the specified Comparison Type uses case-sensitive matching. Therefore, the variable ($)ContainsAllText will be updated to the following:
false
Text contains text that matches all of the patterns in Texts To Find
This example will check whether "The quick brown fox jumps over the lazy dog" contains text that matches all of the patterns in ["?he", "?uick", "*?own", "fox"].
($)ContainsAllText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" contains text that matches all of the patterns in ["?he", "?uick", "*?own", "fox"]. Therefore, the variable ($)ContainsAllText will be updated to the following:
true
Text contains text that matches all of the regexes in Texts To Find
This example will check whether "The quick brown fox jumps over the lazy dog" contains text that matches all of the regexes in ["^The", "(quick|fast)", "b.* ", "(fox|Fox)"].
($)ContainsAllText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" contains text that matches all of the regexes in ["^The", "(quick|fast)", "b.* ", "(fox|Fox)"]. Therefore, the variable ($)ContainsAllText will be updated to the following:
true
Properties
Text
The Text to check whether it contains all of the texts in the given set of Texts To Find.
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Thrown when Search Options is SearchOptions.Regex and one or more items in Texts To Find are not a valid regex (e.g. ().
Remarks
Comparison Types
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null or empty Text
If Text is null or empty (i.e. ""), the variable specified in the Contains All Text property is set to false.
Null or empty Texts To Find
If Texts To Find is empty or contains any null or empty (i.e. "") text, the variable specified in the Contains All Text property is set to false.
Known Limitations
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
6.3.20.2.2 - Contains Any Text
Checks if text contains any of the texts in a given set of texts.
($)ContainsAnyText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" contains the text "The" and "fox" in ["The", "fast", "red", "fox"]. Therefore, the variable ($)ContainsAnyText will be updated to the following:
true
Text does not contain any of the texts in Texts To Find
This example will check whether "The quick brown fox jumps over the lazy dog" contains at least one of the texts in ["the", "slow", "red", "Fox"].
($)ContainsAnyText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" does not contain any of the texts in ["the", "slow", "red", "Flow"]; "slow" and "red" are both missing, and "the" and "Fox" do not match "The" and "fox" respectively as the specified Comparison Type uses case-sensitive matching. Therefore, the variable ($)ContainsAnyText will be updated to the following:
false
Text contains text that matches any of the patterns in Texts To Find
This example will check whether "The quick brown fox jumps over the lazy dog" contains text that matches any of the patterns in ["?he", "Q?ick", "B*?wn", "Fox"].
($)ContainsAnyText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" contains text that matches one of the patterns in ["?he", "Q?ick", "B*?wn", "Fox"]; "?he" matches "The" and "the". Therefore, the variable ($)ContainsAnyText will be updated to the following:
true
Text contains text that matches any of the regexes in Texts To Find
This example will check whether "The quick brown fox jumps over the lazy dog" contains text that matches any of the regexes in ["^The", "(Quick|Fast)", "b.* ", "(fox|Fox)$"].
($)ContainsAnyText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" contains text that matches any of the regexes in ["^The", "(Quick|Fast)", "b.* ", "(fox|Fox)$"]; "^The" matches "The" at the start of the sentence. Therefore, the variable ($)ContainsAnyText will be updated to the following:
true
Properties
Text
The Text to check whether it contains any of the texts in the given set of Texts To Find.
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Thrown when Search Options is SearchOptions.Regex and one or more items in Texts To Find are not a valid regex (e.g. ().
Remarks
Comparison Types
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null or empty Text
If Text is null or empty (i.e. ""), the variable specified in the Contains Any Text property is set to false.
Null or empty Texts To Find
If Texts To Find is empty or only contains null or empty (i.e. "") text, the variable specified in the Contains Any Text property is set to false.
Known Limitations
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
($)ContainsText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" contains the text "quick brown fox". Therefore, the variable ($)ContainsText will be updated to the following:
true
Text does not contain Text To Find
This example will check whether "The quick brown fox jumps over the lazy dog" contains the text "quick red fox".
($)ContainsText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" does not contain "quick red fox". Therefore, the variable ($)ContainsText will be updated to the following:
false
Text contains text that matches the pattern in Text To Find
This example will check whether "The quick brown fox jumps over the lazy dog" contains text that matches the pattern "*?he".
($)ContainsText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" contains "The" and "the" that matches the pattern "?he". Therefore, the variable ($)ContainsText will be updated to the following:
true
Text contains text that matches the regex in Text To Find
This example will check whether "The quick brown fox jumps over the lazy dog" contains text that matches the regex "^The".
($)ContainsText is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" contains "The" at the start of the sentence that matches the regex "^The". Therefore, the variable ($)ContainsText will be updated to the following:
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null or empty Text
If Text is null or empty (i.e. ""), the variable specified in the Contains Text property is set to false.
Null or empty Text To Find
If Text To Find is null or empty (i.e. ""), the variable specified in the Contains Text property is set to false.
Known Limitations
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
6.3.20.3 - Convert To
Convert text to a different format (e.g. "lowercase", "UPPERCASE", "Title Case", "camelCase", "PascalCase").
Converting to camel case will result in all words (except the first) having their first letter capitalized, all other letters lower cased, and all spaces and punctuation being removed (e.g. "TEXT to convert to camel-case!" will be converted to "textToConvertToCamelCase").
Examples
Text converted to camel case
This example will convert "The quick brown fox jumps over the lazy dog" to camel case.
Thrown when the culture identifier of the Culture Info is invalid (e.g. new CultureInfo("InvalidCultureIdentifier")). See Value Is Invalid.
Remarks
Culture Info
For information about the supported values for the CultureInfo property and examples of how it affects casing rules, please see Casing.
Null Culture Info
If Culture Info is null, it will be set to CultureInfo.InvariantCulture.
Null or empty Text
If Text is null or empty (i.e. ""), no operation is performed.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Text converted to camel case and re-assigns it to the variable specified in the Text property.
Converting to lower case will result in all letters being lower cased; spaces and punctuation will be preserved (e.g. "TEXT to convert to lower-case!" will be converted to "text to convert to lower-case!").
Examples
Text converted to lower case
This example will convert "The quick brown fox jumps over the lazy dog" to lower case.
Thrown when the culture identifier of the Culture Info is invalid (e.g. new CultureInfo("InvalidCultureIdentifier")). See Value Is Invalid.
Remarks
Culture Info
For information about the supported values for the CultureInfo property and examples of how it affects casing rules, please see Casing.
Null Culture Info
If Culture Info is null, it will be set to CultureInfo.InvariantCulture.
Null or empty Text
If Text is null or empty (i.e. ""), no operation is performed.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Text converted to lower case and re-assigns it to the variable specified in the Text property.
Converting to pascal case will result in all words having their first letter capitalized, all other letters lower cased, and all spaces and punctuation being removed (e.g. "TEXT to convert to pascal-case!" will be converted to "TextToConvertToPascalCase").
Examples
Text converted to pascal case
This example will convert "The quick brown fox jumps over the lazy dog" to pascal case.
Thrown when the culture identifier of the Culture Info is invalid (e.g. new CultureInfo("InvalidCultureIdentifier")). See Value Is Invalid.
Remarks
Culture Info
For information about the supported values for the CultureInfo property and examples of how it affects casing rules, please see Casing.
Null Culture Info
If Culture Info is null, it will be set to CultureInfo.InvariantCulture.
Null or empty Text
If Text is null or empty (i.e. ""), no operation is performed.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Text converted to pascal case and re-assigns it to the variable specified in the Text property.
Converting to title case will result in all words having their first letter capitalized and all other letters lower cased; except for words that are entirely upper cased, such as acronyms, which remain upper cased; spaces and punctuation will be preserved (e.g. "TEXT to convert to title-case!" will be converted to "TEXT To Convert To Title-Case!").
Examples
Text converted to title case
This example will convert "The quick brown fox jumps over the lazy dog" to title case.
Thrown when the culture identifier of the Culture Info is invalid (e.g. new CultureInfo("InvalidCultureIdentifier")). See Value Is Invalid.
Remarks
Culture Info
For information about the supported values for the CultureInfo property and examples of how it affects casing rules, please see Casing.
Null Culture Info
If Culture Info is null, it will be set to CultureInfo.InvariantCulture.
Null or empty Text
If Text is null or empty (i.e. ""), no operation is performed.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Text converted to title case and re-assigns it to the variable specified in the Text property.
Converting to upper case will result in all letters being upper cased; spaces and punctuation will be preserved (e.g. "TEXT to convert to upper-case!" will be converted to "TEXT TO CONVERT TO UPPER-CASE!").
Examples
Text converted to upper case
This example will convert "The quick brown fox jumps over the lazy dog" to upper case.
Thrown when the culture identifier of the Culture Info is invalid (e.g. new CultureInfo("InvalidCultureIdentifier")). See Value Is Invalid.
Remarks
Culture Info
For information about the supported values for the CultureInfo property and examples of how it affects casing rules, please see Casing.
Null Culture Info
If Culture Info is null, it will be set to CultureInfo.InvariantCulture.
Null or empty Text
If Text is null or empty (i.e. ""), no operation is performed.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Text converted to upper case and re-assigns it to the variable specified in the Text property.
6.3.20.4 - Find And Remove Text
Find text in another text, and remove it.
6.3.20.4.1 - Find And Remove All Text
Finds and removes all occurrences of text from a given text.
As this example is performing a case-sensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" only contains the text "The" once; "the" has a different case so does not match. Therefore, the variable ($)Text will be updated to the following:
" quick brown fox jumps over the lazy dog"
Remove all occurrences of Text To Remove (Ordinal Ignore Case)
This example will find and remove all occurrences of "The" from "The quick brown fox jumps over the lazy dog".
As this example is performing a case-insensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" contains the text "The" twice; the first occurrence is "The" and the second occurrence is "the". Therefore, the variable ($)Text will be updated to the following:
" quick brown fox jumps over lazy dog"
Remove all occurrences that match the pattern in Text To Remove
This example will find and remove all occurrences of text that match the pattern "?he" from "The quick brown fox jumps over the lazy dog".
"The quick brown fox jumps over the lazy dog" contains "The" and "the" that matches the pattern "?he". Therefore, the variable ($)Text will be updated to the following:
" quick brown fox jumps over lazy dog"
Remove all occurrences that match the regex in Text To Remove
This example will find and remove all occurrences of text that match the regex "^The" from "The quick brown fox jumps over the lazy dog".
"The quick brown fox jumps over the lazy dog" contains "The" at the start of the sentence that matches the regex "^The". Therefore, the variable ($)Text will be updated to the following:
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null or empty Text
If Text is null or empty (i.e. "") there is nothing to remove from, so no operation is performed.
Null or empty Text To Remove
If Text To Remove is null or empty (i.e. "") there is nothing to remove, so no operation is performed.
Text To Remove is not present
If Text To Remove is not present there is nothing to remove, so no operation is performed.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String with all occurrences of Text To Remove removed and re-assigns it to the variable specified in the Text property.
Known Limitations
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
6.3.20.4.2 - Find And Remove Text
Finds and removes the specified occurrence of text from a given text.
An Occurrence of 1 means find and remove the first occurrence; 2 means second etc.
As this example is performing a case-sensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" only contains the text "The" once; "the" has a different case so does not match. Therefore, the variable ($)Text will be updated to the following:
" quick brown fox jumps over the lazy dog"
Remove the last Occurrence of Text To Remove (Ordinal Ignore Case)
This example will find and remove the last occurrence of "The" from "The quick brown fox jumps over the lazy dog".
An Occurrence of -1, means find and remove the last occurrence; -2 means second last etc.
As this example is performing a case-insensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" contains the text "The" twice; the first occurrence is "The" and the second and last occurrence is "the". Therefore, the variable ($)Text will be updated to the following:
"The quick brown fox jumps over lazy dog"
Remove the first Occurrence matching the pattern in Text To Remove
This example will find and remove the first occurrence of text matching the pattern "?he" from "The quick brown fox jumps over the lazy dog".
An Occurrence of 1 means find and remove the first occurrence; 2 means second etc.
"The quick brown fox jumps over the lazy dog" contains two occurrences that match the pattern "?he"; the first occurrence is "The" and the second occurrence is "the". Therefore, the variable ($)Text will be updated to the following:
" quick brown fox jumps over the lazy dog"
Remove the last Occurrence matching the regex in Text To Remove
This example will find and remove the last occurrence of text matching the regex "(fox|dog)" from "The quick brown fox jumps over the lazy dog".
An Occurrence of -1, means find and remove the last occurrence; -2 means second last etc.
"The quick brown fox jumps over the lazy dog" contains two occurrences that match the regex "(fox|dog)"; the first occurrence is "fox" and the second and last occurrence is "dog". Therefore, the variable ($)Text will be updated to the following:
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null or empty Text
If Text is null or empty (i.e. "") there is nothing to remove from, so no operation is performed.
Null or empty Text To Remove
If Text To Remove is null or empty (i.e. "") there is nothing to remove, so no operation is performed.
Text To Remove or Occurrence is not present
If Text To Remove or the specified Occurrence is not present, there is nothing to remove, so no operation is performed.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String with the specified Occurrence of Text To Remove removed and re-assigns it to the variable specified in the Text property.
Known Limitations
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
6.3.20.5 - Find And Replace Text
Find text in another text, and replace it.
6.3.20.5.1 - Find And Replace All Text
Finds and replaces all occurrences of text in a given text.
As this example is performing a case-sensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" only contains the text "The" once; "the" has a different case so does not match. Therefore, the variable ($)Text will be updated to the following:
"a quick brown fox jumps over the lazy dog"
Replace all occurrences of Text To Replace (Ordinal Ignore Case)
This example will find and replace all occurrences of "The" in "The quick brown fox jumps over the lazy dog" with "a".
As this example is performing a case-insensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" contains the text "The" twice; the first occurrence is "The" and the second occurrence is "the". Therefore, the variable ($)Text will be updated to the following:
"a quick brown fox jumps over a lazy dog"
Replace all occurrences that match the pattern in Text To Replace
This example will find and replace all occurrences of text that match the pattern "?he" from "The quick brown fox jumps over the lazy dog" with "a".
"The quick brown fox jumps over the lazy dog" contains "The" and "the" that matches the pattern "?he". Therefore, the variable ($)Text will be updated to the following:
"a quick brown fox jumps over a lazy dog"
Replace all occurrences that match the regex in Text To Replace
This example will find and replace all occurrences of text that match the regex "^The" from "The quick brown fox jumps over the lazy dog" with "a".
"The quick brown fox jumps over the lazy dog" contains "The" at the start of the sentence that matches the regex "^The". Therefore, the variable ($)Text will be updated to the following:
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null or empty Text
If Text is null or empty (i.e. "") there is nothing to replace in, so no operation is performed.
Null or empty Text To Replace
If Text To Replace is null or empty (i.e. "") there is nothing to replace, so no operation is performed.
Null or empty Replacement Text
If Replacement Text is null or empty (i.e. "") all occurrences of Text To Replace are replaced with an empty text (i.e. "").
Text To Replace is not present
If Text To Replace is not present there is nothing to replace, so no operation is performed.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String with all occurrences of Text To Replace replaced and re-assigns it to the variable specified in the Text property.
Known Limitations
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
6.3.20.5.2 - Find And Replace Text
Finds and replaces the specified occurrence of text in a given text.
An Occurrence of 1 means find and replace the first occurrence; 2 means second etc.
As this example is performing a case-sensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" only contains the text "The" once; "the" has a different case so does not match. Therefore, the variable ($)Text will be updated to the following:
"a quick brown fox jumps over the lazy dog"
Replace the last occurrence of Text To Replace (Ordinal Ignore Case)
This example will find and replace the last occurrence of "The" in "The quick brown fox jumps over the lazy dog" with "a".
An Occurrence of -1, means find and replace the last occurrence; -2 means second last etc.
As this example is performing a case-insensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" contains the text "The" twice; the first occurrence is "The" and the second and last occurrence is "the". Therefore, the variable ($)Text will be updated to the following:
"The quick brown fox jumps over a lazy dog"
Replace the first Occurrence matching the pattern in Text To Replace
This example will find and replace the first occurrence of text matching the pattern "?he" from "The quick brown fox jumps over the lazy dog" with "a".
An Occurrence of 1 means find and replace the first occurrence; 2 means second etc.
"The quick brown fox jumps over the lazy dog" contains two occurrences that match the pattern "?he"; the first occurrence is "The" and the second occurrence is "the". Therefore, the variable ($)Text will be updated to the following:
"a quick brown fox jumps over the lazy dog"
Replace the last Occurrence matching the regex in Text To Replace
This example will find and replace the last occurrence of text matching the regex "(fox|dog)" from "The quick brown fox jumps over the lazy dog" with "cat".
An Occurrence of -1, means find and replace the last occurrence; -2 means second last etc.
"The quick brown fox jumps over the lazy dog" contains two occurrences that match the regex "(fox|dog)"; the first occurrence is "fox" and the second and last occurrence is "dog". Therefore, the variable ($)Text will be updated to the following:
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null or empty Text
If Text is null or empty (i.e. "") there is nothing to replace in, so no operation is performed.
Null or empty Text To Replace
If Text To Replace is null or empty (i.e. "") there is nothing to replace, so no operation is performed.
If Text To Replace or the specified Occurrence is not present there is nothing to replace, so no operation is performed.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String with the specified Occurrence of Text To Replace replaced and re-assigns it to the variable specified in the Text property.
Known Limitations
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
6.3.20.6 - Format Text
Format text containing format parameters (i.e. {0}) by replacing them with other values.
6.3.20.6.1 - Format Text With Value
Formats text by replacing all {0} format parameters in a specified format template with a given value.
Replaces all {0} format parameters in the specified Format Template with the given Value, saving the result as Text.
An additional Format Provider option can be specified to define the cultural rules used to control the formatting (e.g. new CultureInfo("en-US") will apply American English rules to the formatting).
Examples
Text Value
This example will format "Hello {0}" with "world!".
If Format Template is not specified, null or empty (i.e. ""), or does not contain any {0} format parameters, nothing is replaced; Text will be set to the value of Format Template.
For information about format templates and parameters, please see Text Formatting.
Format Provider can be specified to define the cultural rules used to control the formatting (e.g. new CultureInfo("en-US") will apply American English rules to the formatting.).
If Format Provider is not specified or null, CultureInfo.InvariantCulture will be used; CultureInfo.InvariantCulture is associated with the English language but not with any country/region. For more information, please see Invariant Culture rules.
Thrown when Format Template contains a format parameter not equal to zero (e.g. "Hello {1}").
Thrown when Format Template contains a format parameter that is invalid or not well-formed (e.g. "Cost is {0:Q2}, as "Q" is not a valid format parameter).
Remarks
Text Formatting
Please note that changes to operating system settings, could result in some of the examples above displaying different results.
For information about format templates and parameters, please see Text Formatting.
Null or Empty Format Template
If Format Template is not specified, null or empty (i.e. ""), or does not contain any {0} format parameters, nothing is replaced; Text will be set to the value of Format Template.
Null Format Provider
If Format Provider is not specified or null, CultureInfo.InvariantCulture will be used; CultureInfo.InvariantCulture is associated with the English language but not with any country/region. For more information, please see Invariant Culture rules.
6.3.20.6.2 - Format Text With Values
Formats text by replacing all format parameters (e.g. {0} or {1} or {2}) in a specified format template with given values.
Replaces all format parameters (e.g. {0} or {1} or {2}) in the given Format Template with the specified Values, saving the result as Text.
An additional Format Provider option can be specified to define the cultural rules used to control the formatting (e.g. new CultureInfo("en-US") will apply American English rules to the formatting).
Examples
Text Values
This example will format "Hello {0} {1}" with ["Mr", "Smith"].
($)Text is a variable that will be set to a String value
Result
Formatting "Hello {0} {1}" with ["Mr", "Smith"] results in the variable ($)Text being updated to the following:
"Hello Mr Smith"
Multiple non-text values using American English (“en-US”)
This example will format "Your latest payment of {0:C2} has been received. You have paid {1:P0} of your total and have {2:C2} outstanding." with [99.99, 0.8, 40].
The format parameter {0:C2} will display the 99.99 as U.S currency to two decimal places (i.e. $99.99):
0 - is replaced by the double value 99.99.
C - indicates to include the currency symbol for the specified culture (i.e. $).
2 - indicates to format the double value to two decimal places.
The format parameter {1:P0} will display the 0.8 as a percentage to zero decimal places (i.e. 80 %):
1 - is replaced by the double value 0.8.
P - indicates the value should be formatted as a percentage.
0 - indicates to format the percentage value to zero decimal places.
The format parameter {2:C2} will display the 40 as U.S currency to two decimal places (i.e. $40.00):
2 - is replaced by the double value 40.
C - indicates to include the currency symbol for the specified culture (i.e. $).
2 - indicates to format the double value to two decimal places.
For information about format templates and parameters, please see Text Formatting.
($)Text is a variable that will be set to a String value
Result
"Your latest payment of {0:C2} has been received. You have paid {1:P0} of your total and have {2:C2} outstanding." with [99.99, 0.8, 40] results in the variable ($)Text being updated to the following:
"Your latest payment of $99.99 has been received. You have paid 80 % of your total and have $40.00 outstanding."
Properties
Format Template
Format Template can be specified to define the format of the resultant Text.
All format parameters (e.g. {0} or {1} or {2}) in Format Template will be replaced with the corresponding value in Values. Format parameter {0} will be replaced with the first value in Values; {1} will be replaced with the second value in Values etc.
The number of unique format parameters must be equal to or less than the number of items in Values.
The index of each format parameter must be equal to or less than the number of items in Values - 1.
If Format Template is not specified, null or empty (i.e. ""), or does not contain any format parameters, nothing is replaced; Text will be set to the value of Format Template.
For information about format templates and parameters, please see Text Formatting.
If a value does not have a corresponding format parameter, it is ignored.
Values does not have to contain all text values, it can contain any data types. Any non-text values will be converted to their text representation when they are replaced.
If any value is null or empty (i.e. ""), an empty text (i.e. "") will replace the corresponding format parameter.
For information about how types are converted to their text representation please see Converting Objects To Text.
Format Provider can be specified to define the cultural rules used to control the formatting (e.g. new CultureInfo("en-US") will apply American English rules to the formatting.).
If Format Provider is not specified or null, CultureInfo.InvariantCulture will be used; CultureInfo.InvariantCulture is associated with the English language but not with any country/region. For more information, please see Invariant Culture rules.
Thrown when Format Template contains a format parameter less than zero (e.g. "Hello {-1}") or greater than the count of Values - 1.
Thrown when Format Template contains a format parameter that is invalid or not well-formed (e.g. "Cost is {0:Q2}, as "Q" is not a valid format parameter).
Please note that changes to operating system settings, could result in some of the examples above displaying different results.
For information about format templates and parameters, please see Text Formatting.
Null or Empty Format Template
If Format Template is not specified, null or empty (i.e. ""), or does not contain any format parameters, nothing is replaced; Text will be set to the value of Format Template.
Null Format Provider
If Format Provider is not specified or null, CultureInfo.InvariantCulture will be used; CultureInfo.InvariantCulture is associated with the English language but not with any country/region. For more information, please see Invariant Culture rules.
6.3.20.7 - Get Index(es) of Text
Get the index for the specified occurrence of text, or the indexes of all occurrences of text contained in another text.
6.3.20.7.1 - Get Index Of Text
Gets the index of the specified occurrence of a text in another text.
($)Index is a variable that will be set to an Int32 value
Result
An Occurrence of 1 means get the index of the first occurrence; 2 means second etc.
As this example is performing a case-sensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" only contains the text "The" once; "the" has a different case so does not match. Therefore, the variable ($)Index will be updated to the following:
0
where 0 indicates the index of the first character of the first and only occurrence matching "The".
Get the Index of the last Occurrence of Text To Find (Ordinal Ignore Case)
This example will get the index of the last occurrence of "The" in "The quick brown fox jumps over the lazy dog".
($)Index is a variable that will be set to an Int32 value
Result
An Occurrence of -1 means get the index of the last occurrence; 2 means second last etc.
As this example is performing a case-insensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" contains the text "The" twice; the first occurrence is "The" and the second and last occurrence is "the". Therefore, the variable ($)Index will be updated to the following:
31
where 31 indicates the index of the first character of the last matching occurrence, "the".
Text does not contain Text To Find
This example will attempt to get the index of the first occurrence of "slow" in "The quick brown fox jumps over the lazy dog".
($)Index is a variable that will be set to an Int32 value
Result
"The quick brown fox jumps over the lazy dog" does not contain the text "slow", so the index cannot be found. Therefore, the variable ($)Index will be updated to the following:
-1
where -1 indicates that there are no matching occurrences.
Get the Index of the first Occurrence matching the pattern in Text To Find
This example will get the index of the first occurrence of text matching the pattern "?he" from "The quick brown fox jumps over the lazy dog".
($)Index is a variable that will be set to an Int32 value
Result
An Occurrence of 1 means get the index of the first occurrence; 2 means second etc.
"The quick brown fox jumps over the lazy dog" contains two occurrences that match the pattern "?he"; the first occurrence is "The" and the second occurrence is "the". Therefore, the variable ($)Index will be updated to the following:
0
where 0 indicates the index of the first character of the first occurrence matching the pattern "?he".
Get the Index of the last Occurrence matching the regex in Text To Remove
This example will get the index of the last occurrence of text matching the regex "(fox|dog)" from "The quick brown fox jumps over the lazy dog".
($)Index is a variable that will be set to an Int32 value
Result
An Occurrence of -1 means get the index of the last occurrence; 2 means second last etc.
"The quick brown fox jumps over the lazy dog" contains two occurrences that match the regex "(fox|dog)"; the first occurrence is "fox" and the second and last occurrence is "dog". Therefore, the variable ($)Index will be updated to the following:
40
where 0 indicates the index of the first character of the last occurrence matching the regex "(fox|dog)".
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null or empty Text
If Text is null or empty (i.e. ""), the variable specified in the Index property is set to -1.
Null or empty Text To Find
If Text To Find is null or empty (i.e. ""), the variable specified in the Index property is set to -1.
Occurrence is zero
If the Occurrence is set to 0, the variable specified in the Index property is set to -1.
Occurrence of Text To Find not found
If the specified Occurrence of Text To Find is not found in Text, the variable specified in the Index property is set to -1.
Known Limitations
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
6.3.20.7.2 - Get Indexes Of Text
Gets the indexes of all occurrences of a text in another text.
($)Indexes is a variable that will be set to an IList<Int32> value
Result
As this example is performing a case-sensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" only contains the text "The" once; "the" has a different case so does not match. Therefore, the variable ($)Indexes will be updated to the following:
[0]
where 0 indicates the index of the first character of the matching "The" occurrence.
Get Indexes of all occurrences of Text To Find (Ordinal Ignore Case)
This example will get the indexes of all occurrences of "The" in "The quick brown fox jumps over the lazy dog".
($)Indexes is a variable that will be set to an IList<Int32> value
Result
As this example is performing a case-insensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" contains the text "The" twice; the first occurrence is "The" and the second occurrence is "the". Therefore, the variable ($)Indexes will be updated to the following:
[0,31]
where 0 indicates the index of the first character of the matching "The" occurrence, and 31 indicates the index of the first character of the matching "the" occurrence.
Text does not contain Text To Find
This example will attempt to get the indexes of all occurrences of "slow" in "The quick brown fox jumps over the lazy dog".
($)Indexes is a variable that will be set to an IList<Int32> value
Result
"The quick brown fox jumps over the lazy dog" does not contain the text "slow", so the index cannot be found. Therefore, the variable ($)Indexes will be updated to the following:
[-1]
where -1 indicates that there are no matching occurrences.
Get Indexes of all occurrences matching the pattern in Text To Find
This example will get the indexes of all occurrences of text matching the pattern "?he" from "The quick brown fox jumps over the lazy dog".
($)Indexes is a variable that will be set to an IList<Int32> value
Result
"The quick brown fox jumps over the lazy dog" contains two occurrences that match the pattern "?he"; the first occurrence is "The" and the second occurrence is "the". Therefore, the variable ($)Indexes will be updated to the following:
[0,31]
where 0 indicates the index of the first character of the matching "The" occurrence, and 31 indicates the index of the first character of the matching "the" occurrence.
Get Indexes of all occurrences matching the regex in Text To Remove
This example will get the indexes of all occurrences of text matching the regex "(fox|dog)" from "The quick brown fox jumps over the lazy dog".
($)Indexes is a variable that will be set to an IList<Int32> value
Result
"The quick brown fox jumps over the lazy dog" contains two occurrences that match the regex "(fox|dog)"; the first occurrence is "fox" and the second and last occurrence is "dog". Therefore, the variable ($)Indexes will be updated to the following:
[16,40]
where 16 indicates the index of the first character of the matching "fox" occurrence, and 40 indicates the index of the first character of the matching "dog" occurrence.
* wildcard character can be used to match 0 or more characters.
? wildcard character can be used to match 0 or 1 character.
All other characters are treated as a literal character.
SearchOptions.Regex allows regex text matching using .Net Regex Syntax.
Please note that with SearchOptions.ContainsText overlapping matches are detected (e.g. searching for "aa" in "aaa" matches "aa" at index 0 and "aa" at index 1). With SearchOptions.Regex only "aa" at index 0 will be matched.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null or empty Text
If Text is null or empty (i.e. ""), the variable specified in the Indexes property is set to [-1].
Null or empty Text To Find
If Text To Find is null or empty (i.e. ""), the variable specified in the Indexes property is set to [-1].
Text To Find not found
If Text To Find is not found in Text, the variable specified in the Indexes property is set to [-1].
Known Limitations
If Search Options is set to SearchOptions.Regex or SearchOptions.PatternMatching and Comparison Type is set to StringComparison.CurrentCulture, some characters such as æ that is equivalent to ae may not evaluate as equal.
($)TextAtBeginning is a variable that will be set to a String
Result
Getting the first 3 characters from the beginning of "ABCDEFGHIJKLMNOPQRSTUVWXYZ" results in the variable ($)TextAtBeginning being updated to the following:
($)TextAtIndex is a variable that will be set to a String
Result
"D" is at index 3 in "ABCDEFGHIJKLMNOPQRSTUVWXYZ". Therefore, getting 3 characters at (and including) index 3 results in the variable ($)TextAtIndex being updated to the following:
($)TextBeforeIndex is a variable that will be set to a String
Result
"D" is at index 3 in "ABCDEFGHIJKLMNOPQRSTUVWXYZ". Therefore, getting 3 characters before index 3 results in the variable ($)TextBeforeIndex being updated to the following:
($)TextBetweenIndexes is a variable that will be set to a String
Result
"A" is at index 0 and "D" is at index 3 in "ABCDEFGHIJKLMNOPQRSTUVWXYZ". Therefore, getting all characters between (and including) start index 0 and end index 3 results in the variable ($)TextBetweenIndexes being updated to the following:
"ABCD"
Get text where Start Index is greater than End Index
This example will get all characters between start index 3 and end index 0 of "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
($)TextBetweenIndexes is a variable that will be set to a String
Result
In this example the start index 3 is greater than the end index 0. When this occurs, the block simply swaps the indexes before it processes the text.
Therefore, having start index 3 and end index 0 is the same as having start index 0 and end index 3.
"A" is at index 0 and "D" is at index 3 in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
Therefore, getting all characters between (and including) start index 3 and end index 0, or start index 0 and end index 3, results in the variable ($)TextBetweenIndexes being updated to the following:
The Start Index and End Index properties are both inclusive indexes, which means the characters at those indexes will be included in the retrieved text.
Start Index greater than End Index
Start Index can be greater than End Index. If this is the case, the values of the indexes will be swapped. See Example above.
6.3.20.10 - Is Text
Check if text is equal to another text, null, empty (i.e. ""), or whitespace (e.g. " ").
($)TextIsEmptyOrWhitespace is a variable that will be set to a Boolean value
Result
null is not empty (i.e. "") or whitespace (i.e. space, tab, carriage return, line feed characters), resulting in the variable ($)TextIsEmptyOrWhitespace being updated to the following:
false
Text is not empty or whitespace
This example will check if "The quick brown fox jumps over the lazy dog" is empty (i.e. "") or whitespace (i.e. space, tab, carriage return, line feed characters).
($)TextIsEmptyOrWhitespace is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" is not empty (i.e. "") or whitespace (i.e. space, tab, carriage return, line feed characters), resulting in the variable ($)TextIsEmptyOrWhitespace being updated to the following:
false
Properties
Text
The Text to check is empty (i.e. "") or whitespace (i.e. space, tab, carriage return, line feed characters).
If the Text is empty (i.e. "") or whitespace (i.e. space, tab, carriage return, line feed characters), the specified variable will be set to true, otherwise it will be set to false.
($)TextIsEqual is a variable that will be set to a Boolean value
Result
As this example is performing a case-sensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" is equal to "The quick brown fox jumps over the lazy dog", as they match exactly, including casing. Therefore, the variable ($)TextIsEqual will be updated to the following:
true
Text is not equal to Text To Compare (Ordinal)
This example will check if "The quick brown fox jumps over the lazy dog" is equal to "the quick brown fox jumps over the lazy dog".
($)TextIsEqual is a variable that will be set to a Boolean value
Result
As this example is performing a case-sensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" is not equal to "the quick brown fox jumps over the lazy dog", as whilst the characters match exactly, the casing of the first "T" differs. Therefore, the variable ($)TextIsEqual will be updated to the following:
false
Text is equal to Text To Compare (Ordinal Ignore Case)
This example will check if "The quick brown fox jumps over the lazy dog" is equal to "the quick brown fox jumps over the lazy dog".
($)TextIsEqual is a variable that will be set to a Boolean value
Result
As this example is performing a case-insensitive, culture-insensitive comparison of text, "The quick brown fox jumps over the lazy dog" is equal to "the quick brown fox jumps over the lazy dog", as the characters match exactly, and casing is not considered. Therefore, the variable ($)TextIsEqual will be updated to the following:
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
For information about the supported values for the Comparison Type property and examples of how it is determined whether two pieces of text match, please see Equality.
Null vs empty
If Text is null and Text To Compare is empty (i.e. ""), or vice versa, the variable specified in the Text Is Equal property is set to false, as null and "" are not equal.
($)TextIsNullOrEmpty is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" is not null or empty (i.e. ""), resulting in the variable ($)TextIsNullOrEmpty being updated to the following:
($)TextIsNullEmptyOrWhitespace is a variable that will be set to a Boolean value
Result
" " is whitespace (i.e. space, tab, carriage return, line feed characters), resulting in the variable ($)TextIsNullEmptyOrWhitespace being updated to the following:
true
Text is not null, empty or whitespace
This example will check if "The quick brown fox jumps over the lazy dog" is null, empty (i.e. "") or whitespace (i.e. space, tab, carriage return, line feed characters).
($)TextIsNullEmptyOrWhitespace is a variable that will be set to a Boolean value
Result
"The quick brown fox jumps over the lazy dog" is not null, empty (i.e. "") or whitespace (i.e. space, tab, carriage return, line feed characters), resulting in the variable ($)TextIsNullEmptyOrWhitespace being updated to the following:
false
Properties
Text
The Text to check is null, empty (i.e. "") or whitespace (i.e. space, tab, carriage return, line feed characters).
The result of the is null, empty or whitespace check.
If the Text is null, empty (i.e. "") or whitespace (i.e. space, tab, carriage return, line feed characters), the specified variable will be set to true, otherwise it will be set to false.
Join a set of values together (using a separator) to create text.
6.3.20.11.1 - Join Text
Joins a set of values together as text, using the given separator between each value.
Join Text
(Cortex.Blocks.Text.JoinText.JoinTextBlock`1)
Description
Joins a set of Values together as Text, using the given Separator between each value.
Examples
Join a set of String Values together with a pipe Separator
This example will join the set of String values, ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], together with a pipe separator (i.e. "|").
($)Text is a variable that will be set to a String
Result
Joining ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] together as text with a pipe separator (i.e. "|"), results in the variable ($)Text being updated to the following:
Thrown when Length is greater than the length of Text.
Remarks
Negative Length
If Length is negative, all text will be removed and the variable specified in the Text property will be set to empty (i.e. "").
Zero Length
If Length is 0, no text will be removed and the variable specified in the Text property will remain unchanged.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Length of text removed at the beginning and re-assigns it to the variable specified in the Text property.
6.3.20.12.2 - Remove Text At End
Removes a length of text from the end of a given text.
Thrown when Length is greater than the length of Text.
Remarks
Negative Length
If Length is negative, all text will be removed and the variable specified in the Text property will be set to empty (i.e. "").
Zero Length
If Length is 0, no text will be removed and the variable specified in the Text property will remain unchanged.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Length of text removed at the end and re-assigns it to the variable specified in the Text property.
6.3.20.12.3 - Remove Text At Index
Removes a length of text at the specified index of a given text.
"D" is at index 3 in "ABCDEFGHIJKLMNOPQRSTUVWXYZ". Therefore, removing 3 characters at (and including) index 3 results in the variable ($)Text being updated to the following:
Thrown when Index is less than zero or greater than the length of Text - 1.
Thrown when Index + a positive Length is greater than the length of Text - 1.
Remarks
Negative Length
A negative Length can be used to remove all text at and after the Index of Text.
Zero Length
If Length is 0, no text will be removed and the variable specified in the Text property will remain unchanged.
Index is inclusive
The Index property is an inclusive index, which means the character at the index will be included in the removed text.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Length of text removed at the specified Index and re-assigns it to the variable specified in the Text property.
6.3.20.12.4 - Remove Text Before Index
Removes a length of text before the specified index of a given text.
"D" is at index 3 in "ABCDEFGHIJKLMNOPQRSTUVWXYZ". Therefore, removing 3 characters before index 3 results in the variable ($)Text being updated to the following:
Thrown when Index is less than 1 or greater than the length of Text - 1.
Thrown when Index - a positive Length is less than 1.
Remarks
Negative Length
A negative Length can be used to remove all text before the Index of Text.
Zero Length
If Length is 0, the variable specified in the Text property will be set to empty (i.e. "").
Index is exclusive
The Index property is an exclusive index, which means the character at the index will not be included in the removed text.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the Length of text removed before the specified Index and re-assigns it to the variable specified in the Text property.
6.3.20.12.5 - Remove Text Between Indexes
Removes text between the specified start index and end index of a given text.
"A" is at index 0 and "D" is at index 3 in "ABCDEFGHIJKLMNOPQRSTUVWXYZ". Therefore, removing all characters between (and including) start index 0 and end index 3 results in the variable ($)Text being updated to the following:
"EFGHIJKLMNOPQRSTUVWXYZ"
Remove text where Start Index is greater than End Index
This example will remove all characters between start index 3 and end index 0 of "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
In this example the start index 3 is greater than the end index 0. When this occurs, the block simply swaps the indexes before it processes the text.
Therefore, having start index 3 and end index 0 is the same as having start index 0 and end index 3.
"A" is at index 0 and "D" is at index 3 in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
Therefore, removing all characters between (and including) start index 3 and end index 0, or start index 0 and end index 3, results in the variable ($)Text being updated to the following:
The Start Index and End Index properties are both inclusive indexes, which means the characters at those indexes will be included in the removed text.
Start Index greater than End Index
Start Index can be greater than End Index. If this is the case, the values of the indexes will be swapped. See Example above.
Immutable String data type
The String data type used to represent Text is immutable, which means it is read-only and cannot be changed once created.
To overcome this, this block creates a new String which has the text removed between the specified Start Index and End Index, and re-assigns it to the variable specified in the Text property.
6.3.20.13 - Split Text
Split text (using a separator) into a list of values.
6.3.20.13.1 - Split Text
Splits text into a list of String values, using the given separator to determine where to split.
Split Options can be used to specify how to treat empty entries (i.e. "").
Examples
Split Text into a list of String Values using a pipe Separator
This example will split the text "Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday" into a list of String values, using the pipe separator (i.e. "|") to determine where to split.
($)Values is a variable that will be set to an IList<String>
Result
Splitting "Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday" using a pipe separator (i.e. "|"), results in the variable ($)Values being updated to the following:
Split Text into a list of String Values using a comma Separator (removing empty entries)
This example will split the text "1,2,3,," into a list of String values, using the comma separator (i.e. ",") to determine where to split, and removing empty entries (i.e. "").
($)Values is a variable that will be set to an IList<String>
Result
Splitting "1,2,3,," using a comma separator (i.e. ",") and removing the last 2 entries which are empty (i.e. ""), results in the variable ($)Values being updated to the following:
["1","2","3"]
Split Text into a list of String Values using a comma Separator (keeping empty entries)
This example will split the text "1,2,3,," into a list of String values, using the comma separator (i.e. ",") to determine where to split, and keeping empty entries (i.e. "").
($)Values is a variable that will be set to an IList<String>
Result
Splitting "1,2,3,," using a comma separator (i.e. ",") and keeping the last 2 entries which are empty, results in the variable ($)Values being updated to the following:
Any type of Value can be set, including Lists, Dictionaries, Structures etc.
If a Variable is set to the Value of another Variable that is a Reference Type then they will refer to the same instance. This means that if either Variable has new items added to it, items updated in it, or items removed from it, then both will be affected, please see Reference Types for more information.
If a Variable is set to the Value of another Variable that is a Value Type then they will refer to different instances. This means that if either Variable is updated, then only the updated variable will be affected, please see Value Types for more information.
Examples
Setting a Variable
This example will set a Variable to a list of [[1, 2, 3], [4, 5, 6]].
If a Variable is set to the Value of another Variable that is a Reference Type then they will refer to the same instance. This means that if either Variable has new items added to it, items updated in it, or items removed from it, then both will be affected, please see Reference Types for more information.
If a Variable is set to the Value of another Variable that is a Value Type then they will refer to different instances. This means that if either Variable is updated, then only the updated variable will be affected, please see Value Types for more information.
If the Set Variable block is used to set a Variable that is not initialised, the Variable will be initialised with the given Value when the block is run.
Overwriting Variables
If the Set Variable block is used to set a Variable that is already initialised and has a Value, the Variable will be overwritten with the new Value when the block is run.
Each workspace has its own scope; as a result, variables can be defined that only exist and are accessible in this workspace and any of its sub-workspaces. On exiting a workspace any variables defined for the workspace’s scope are deleted.
The Set Variable block can only set a Variable that is accessible from its scope.
For information about variables and scope, please see Variables.
Null Value
If Value is not provided or is set to null, Variable will be set to null.
6.3.22 - Workspaces
Blocks used to organise flows and group related logic and actions together.
Indicates the end of a workspace; when a flow execution reaches this block it will exit the workspace, and all variables declared in the scope of the workspace are deleted.
A workspace can contain any number of these blocks, and they can be placed anywhere in the workspace.
The block has no block specific properties, but it does have the Description property that is common to all blocks. This allows users to give each block a description; typically this will be left blank for this block.
A breakpoint can be added to this block when debugging.
Examples
No examples for the block.
Properties
No properties for the block, other than the Description property that is common to all blocks.
Exceptions
No exceptions are thrown by the block.
Remarks
Workspace Scope
Each workspace has its own scope; as a result, variables can be defined that only exist and are accessible in this workspace and any of its sub-workspaces. On exiting a workspace any variables defined for the workspace’s scope are deleted.
For information about variables and scope, please see Variables.
Indicates the start of a workspace; when a flow execution reaches this block it will create a new scope for the workspace.
This is always the first block in a workspace. It cannot be deleted, and a workspace can only contain one of these blocks.
The block has no block specific properties, but it does have the Description property that is common to all blocks. This allows users to give each block a description; typically this will be left blank for this block.
A breakpoint can be added to this block when debugging.
Examples
No examples for the block.
Properties
No properties for the block, other than the Description property that is common to all blocks.
Exceptions
No exceptions are thrown by the block.
Remarks
Workspace Scope
Each workspace has its own scope; as a result, variables can be defined that only exist and are accessible in this workspace and any of its sub-workspaces. On exiting a workspace any variables defined for the workspace’s scope are deleted.
For information about variables and scope, please see Variables.
This block represents a new workspace; when a flow execution reaches this block it will move to the Start Workspace block within this block’s workspace; each workspace has its own scope.
The Workspace block can be used to organise block logic into smaller steps with distinct functions. When a new Workspace block is placed on a flow, it will contain a Start Workspace and End Workspace block within its workspace.
If a Workspace block is copied and pasted its workspace is also copied, along with all blocks and variables within its scope.
The block has no block specific properties, but it does have the Description property that is common to all blocks. This allows users to give each block a description; typically this will be left blank for this block. Any description given will become the name for this block’s scope
A breakpoint can be added to this block when debugging.
Examples
No examples for the block.
Properties
No properties for the block, other than the Description property that is common to all blocks, and the Block Timeout property that is common to most blocks.
Exceptions
No exceptions are thrown by the block.
Remarks
Block Restrictions
A workspace can contain any number of blocks. The only restrictions within a workspace are that there can only be one Start Workspace block and one Handle Workspace Exception block within a workspace.
Starting a flow that contains more than one of the restricted blocks within a workspace will cause a Validation Error to occur.
If an exception occurs within the workspace of the Handle Flow Exception block and is not handled, the flow will end with a status of Error.
For more information about chaining of exception handling blocks and passing of exceptions, please see Exception Handling.
Workspace Scope
Each workspace has its own scope; as a result, variables can be defined that only exist and are accessible in this workspace and any of its sub-workspaces. On exiting a workspace any variables defined for the workspace’s scope are deleted.
For information about variables and scope, please see Variables.
The "Cortex_DataTypes_Dictionaries_Structure" root node is added as there is no single top-level key.
The "node1"Key is converted into a child node of "Cortex_DataTypes_Dictionaries_Structure" with its corresponding Item as the value.
The "node2"Key is converted into a child node of "Cortex_DataTypes_Dictionaries_Structure" with its corresponding Item as the value.
The "node3"Key is converted into a child node of "Cortex_DataTypes_Dictionaries_Structure" with its corresponding Item as the value.
Convert a Complex Structure to Xml
This example will convert the Structure below to its Xml representation. This scenario is unlikely unless Xml has been converted to a Structure and is being Round-Tripped.
Thrown when Structure has a key that is an empty string.
Thrown when the Structure includes an xml declaration key (e.g. "?xml" can only accept the following attributes: "@version", "@encoding" and "@standalone".) or a document type definition key (e.g. "!DOCTYPE" can only accept the following attributes: "@name", "@public", "@system" and "@internalSubset").
Thrown when the Structure includes an xml declaration key (e.g. "?xml") with an attribute that has an invalid Primitive Value. (e.g. Key: "@version", Value: false, where "@version" must be a numeric value).
Thrown when the Structure includes a document type definition key (e.g. "!DOCTYPE") that has an attribute with an invalid Primitive Value. (e.g. Key: "@name", Value: 22, where "@name" must be a text value).
Thrown when the Structure includes an attribute key with a Complex Type as a value. (e.g. Key: "@name", Value: new UserCredentials{...}).
Remarks
Attributes
If a Node requires an attribute, the attribute is defined by a Key where the key is the attribute name with an "@" before it and the Item is the attribute data, for example:
An Xml declaration key (e.g. "?xml") can only accept the following attributes: "@version", "@encoding" and "@standalone".
A document type definition key (e.g. "!DOCTYPE") can only accept the following attributes: "@name", "@public", "@system" and "@internalSubset".
"$id", "$ref", "$type", "$value" and "values" are reserved words and should not be used as keys.
Text Nodes
If a key contains a structure as its item, the inner keys are converted into Nodes with their corresponding items as the values. The key "#text" is converted into value of its parent node.
The Structure example above would be converted to the following Xml.
@"<node><innerNodeattribute="attributeValue"> Inner Node Value
</innerNode> Node Value
</node>"
Duplicate Nodes at the Same Level
If there are multiple duplicate nodes at the same level, they are defined using a Key where the key is the duplicated node name and the Item is a list of each of the corresponding duplicate node’s values, for example:
The Structure example above would be converted to the following Xml.
@"<node><duplicateNode> First Duplicate Node
</duplicateNode><duplicateNode> Second Duplicate Node
</duplicateNode><distinctNode> Distinct Node
</distinctNode></node>"
Using Non-Alphanumeric Symbols within Node Names
Any non-alphanumeric symbol (i.e. symbols that are not "0" to "9", "a" to "z", or "A" to "Z") will be converted to their respective Unicode values when used within a Key. For example, "!" and "&" are both non-alphanumeric symbols and would be converted to "x0021" and "x0026" respectively.
For more information on characters and their Unicode values please see Character Sets
"<Cortex_DataTypes_Dictionaries_Structure>" is added as a root node when the Structure has more than one top-level key to ensure that valid Xml is produced.
{"node1":"1","node2":"2","node3":"3"}
The Xml example above would be converted to the following Structure.
($)Xml, with value "<topLevelNode topLevelAttribute=""exampleAttribute""><innerNode innerNodeAttribute=""exampleInnerNodeAttribute""><nestedNode>nested node text</nestedNode>inner node text</innerNode><id>1</id><id>2</id><id>3</id></topLevelNode>"
The node "topLevelNode" is converted into the "topLevelNode" key.
The attribute "topLevelAttribute" is converted into the "@topLevelAttribute" key with its corresponding value as the item.
The node "innerNode" is converted into the "innerNode" key.
The attribute "innerNodeAttribute" is converted into the "@innerNodeAttribute" key with its corresponding value as the item.
The node "nestedNode" is converted into the "nestedNode" key with its corresponding value as the item.
The value of "innerNode" is converted into the "#text" key with its corresponding value as the item.
The three "id" nodes are converted into a single "id" key with each corresponding value being an entry of the item list.
Convert Round-tripped Xml to a Structure
This example will convert the Xml below to its Structure representation.
This example will only occur when a Structure is Converted to Xml using the Convert Structure To Xml block and is then converted again using this block. This is called Round-Tripping.
($)Xml, with value "<Cortex_DataTypes_Dictionaries_Structure><node1>1</node1><node2>2</node2><node3>3</node3></Cortex_DataTypes_Dictionaries_Structure>"
Thrown when the Xml is not valid (i.e the Xml contains an ampersand symbol or is missing a root node).
Remarks
Attributes
If a Node has an attribute, the attribute is converted to a Key where the key is the attribute name with an "@" before it and the value is the attribute data, for example:
If a node contains a value and inner nodes or attributes, the inner nodes and attributes are converted into Keys with their corresponding values as the Items. The value of the node is converted into the "#text" key with its value as the item.
@"<node><innerNodeattribute="attributeValue"> Inner Node Value
</innerNode> Node Value
</node>"
The Xml example above would be converted to the following Structure.
If a node contains duplicate nodes at the same level, they are converted into a Key where the key is the duplicated node name and the Item is a list of each of the corresponding duplicate node’s values, for example:
@"<node><duplicateNode> First Duplicate Node
</duplicateNode><duplicateNode> Second Duplicate Node
</duplicateNode><distinctNode> Distinct Node
</distinctNode></node>"
The Xml example above would be converted to the following Structure.
Any non-alphanumeric symbol (i.e. symbols that are not "0" to "9", "a" to "z", or "A" to "Z") will be converted to their respective Unicode values when used within a node name. For example, "!" and "&" are both non-alphanumeric symbols and would be converted to "x0021" and "x0026" respectively.
For more information on characters and their Unicode values please see Character Sets
The Convert Structure To Xml adds "<Cortex_DataTypes_Dictionaries_Structure>" as a root node when the structure has more than one top-level key to ensure that valid Xml is produced.
When the "<Cortex_DataTypes_Dictionaries_Structure>" root node is converted from Xml to a Structure the root node is removed and any inner nodes become the top-level keys.
The Xml example above would be converted to the following Structure.
{"node1":"1","node2":"2","node3":"3"}
This example will only occur when a Structure is Converted to Xml and is then converted again using this block. This is called Round-Tripping.
6.4 - Data Types
This section includes all reference documentation for data types.
6.4.1 - All
Data types used to represent all other data types.
6.4.1.1 - dynamic
Any data type can be used where a dynamic data type is required. dynamic data type is identical to the Object data type, except for one difference; dynamic data types do not need to be explicitly cast to other data types to be used, whereas Object data types do.
dynamic
Summary
Any data type can be used where a dynamic data type is required.
dynamic data type is identical to the Object data type, except for one difference; dynamic data types do not need to be explicitly cast to other data types to be used, whereas Object data types do.
Category:
All
Name:
dynamic
Full Name:
N/A
Alias:
N/A
Description:
Any data type can be used where a dynamic data type is required. dynamic data type is identical to the Object data type, except for one difference; dynamic data types do not need to be explicitly cast to other data types to be used, whereas Object data types do.
Size:
Varies
Default Value:
null
Can be used as:
Object, dynamic
Can be cast to:
N/A
Remarks
When is the dynamic Data Type Used?
The dynamic data type is only likely to be encountered in the following circumstances:
An Input or InputOutput property of a Block can accept any data type
An Output property of a Block can return any data type
A Collection that contains different data types (e.g. [1, "Text", true]) is saved to a Variable
Also note, in these circumstances it is more likely to encounter the dynamic data type, rather than Object. See Object vs dynamic for more information.
Object vs dynamic
Object and dynamic data types are identical, except for one difference:
Once a variable contains an Object data type, if it needs to be used as its original data type it must be cast back to that data type (e.g. (Int32)($)ObjectVariableContainingAnInteger); a dynamic data type does not.
Property Editor Support
The Expression Editor is available for Input properties where the data type is dynamic.
The Literal Editor is not available for Input properties where the data type is dynamic.
The Variable Editor is available for InputOutput and Output properties where the data type is dynamic.
Any data type can be used where an Object data type is required, as all data types derive from Object.
Object
(System.Object)
Summary
Any data type can be used where an Object data type is required, as all data types derive from Object.
Object data type is identical to the dynamic data type, except for one difference; dynamic data types do not need to be explicitly cast to other data types to be used, whereas Object data types do.
Category:
All
Name:
Object
Full Name:
System.Object
Alias:
object
Description:
Any data type can be used where an Object data type is required, as all data types derive from Object. Object data type is identical to the dynamic data type, except for one difference; dynamic data types do not need to be explicitly cast to other data types to be used, whereas Object data types do.
Size:
Varies
Default Value:
null
Can be used as:
Object, dynamic
Can be cast to:
N/A
Remarks
When is the Object Data Type Used?
The Object data type is only likely to be encountered in the following circumstances:
An Input or InputOutput property of a Block can accept any data type
An Output property of a Block can return any data type
A Collection that contains different data types (e.g. [1, "Text", true]) is saved to a Variable
Also note, in these circumstances it is more likely to encounter the dynamic data type, rather than Object. See Object vs dynamic for more information.
It is also highly unlikely that you will need to create an Object; typically you will create and work with other data types such as String or Int32 that derive from Object. However, if ever required you can create a new object using the following expression:
newObject()
Object vs dynamic
Object and dynamic data types are identical, except for one difference:
Once a variable contains an Object data type, if it needs to be used as its original data type it must be cast back to that data type (e.g. (Int32)($)ObjectVariableContainingAnInteger); a dynamic data type does not.
Property Editor Support
The Expression Editor is available for Input properties where the data type is Object.
The Literal Editor is not available for Input properties where the data type is Object.
The Variable Editor is available for InputOutput and Output properties where the data type is Object.
Data types used for working with collections such as Lists, Dictionaries and Structures.
6.4.2.1 - Array
Any data type representing an array of items. The type of items that can be contained in the array depend upon the type of the array. Common examples include arrays of strings and integers (i.e. String[] and Int32[]).
Array
(System.Array)
Summary
Any data type representing an array of items.
The type of items that can be contained in the array depend upon the type of the array.
Common examples include arrays of strings and integers (i.e. String[] and Int32[]); for more see Most Common Array Data Types.
Arrays are very similar to Lists, but have some key differences, such as they are a fixed size and cannot be added to, or deleted from. For more information about the differences between Arrays and Lists, and when to use each of them see Arrays vs Lists.
Category:
Collections
Name:
Array
Full Name:
System.Array
Alias:
N/A
Description:
Any data type representing an array of items. The type of items that can be contained in the array depend upon the type of the array.
Size:
Varies
Default Value:
null
Can be used as:
IEnumerable, Object, dynamic
Can be cast to:
N/A
Remarks
Most Common Array Data Types
Any of the following data types can be used where an Array is required:
Used to represent a collection of key/item pairs. TKey indicates the data type of the keys used to access the items contained in the collection. TItem indicates the data type of the items contained in the collection. Each TItem can be individually accessed by a key.
The Dictionary<TKey, TItem> data type is used to represent a collection of key/item pairs.
TKey indicates the data type of the keys used to access the items contained in the collection. TItem indicates the data type of the items contained in the collection. Each TItem can be individually accessed by a key.
A collection of key/item pairs. TKey indicates the data type of the keys used to access the items contained in the collection. TItem indicates the data type of the items contained in the collection. Each TItem can be individually accessed by a key.
IEnumerable<KeyValuePair<TKey, TItem>> (e.g. where Dictionary<TKey, TItem> is Dictionary<String, Int32> and IEnumerable<KeyValuePair<TKey, TItem>> is IEnumerable<KeyValuePair<String, Int32>>)
Can be cast to:
N/A
Remarks
Create a Dictionary<TKey, TItem>
The following table shows some of the ways that a Dictionary<TKey, TItem> can be created.
Method
Example
Result
Editor Support
Notes
Use a Dictionary<TKey, TItem> expression
new Dictionary<String, dynamic>()
{}
Expression
Dictionary<String, dynamic> containing zero items
new Dictionary<String, String>() { { "StringKey1", "StringValue" } }
{ "StringKey1": "StringValue" }
Expression
Dictionary<String, String> containing one String item with a String key
The Expression Editor is available for Input properties where the data type is Dictionary<TKey, TItem>.
The Literal Editor is not available for Input properties where the data type is Dictionary<TKey, TItem>.
The Variable Editor is available for InputOutput and Output properties where the data type is Dictionary<TKey, TItem>.
Known Limitations
Currently, only certain data types can be used for TKey. These include, but not limited to:
String
Int32
Double
Boolean
DateTimeOffset
If the data type of TKey is anything other than a String, when viewing the Dictionary<TKey, TItem> in Gateway the key value will be displayed as its ToString() representation (e.g. an Int32 key value of 1 will be displayed as "1" instead of 1).
Any data type representing a collection of key/item pairs. TKey indicates the data type of the keys used to access the items contained in the collection. TItem indicates the data type of the items contained in the collection. Each TItem can be individually accessed by a key. Dictionary<TKey, TItem> is the most common example.
Any data type representing a collection of key/item pairs.
TKey indicates the data type of the keys used to access the items contained in the collection. TItem indicates the data type of the items contained in the collection. Each TItem can be individually accessed by a key.
Dictionary<TKey, TItem> is the most common example.
Any data type representing a collection of key/item pairs. TKey indicates the data type of the keys used to access the items contained in the collection. TItem indicates the data type of the items contained in the collection. Each TItem can be individually accessed by a key.
Size:
Varies
Default Value:
null
Can be used as:
IEnumerable, Object, dynamic
IEnumerable<KeyValuePair<TKey, TItem>> (e.g. where IDictionary<TKey, TItem> is IDictionary<String, Int32> and IEnumerable<KeyValuePair<TKey, TItem>> is IEnumerable<KeyValuePair<String, Int32>>)
Can be cast to:
N/A
Remarks
Most Common IDictionary<TKey, TItem> Data Types
Any of the following data types can be used where an IDictionary<TKey, TItem> is required:
The Expression Editor is available for Input properties where the data type is IDictionary<TKey, TItem>.
The Literal Editor is not available for Input properties where the data type is IDictionary<TKey, TItem>.
The Variable Editor is available for InputOutput and Output properties where the data type is IDictionary<TKey, TItem>.
Known Limitations
Currently, only certain data types can be used for TKey. These include, but not limited to:
String
Int32
Double
Boolean
DateTimeOffset
If the data type of TKey is anything other than a String, when viewing the IDictionary<TKey, TItem> in Gateway the key value will be displayed as its ToString() representation (e.g. an Int32 key value of 1 will be displayed as "1" instead of 1).
Any data type representing a collection of items that can iterated or looped over. The items contained in the collection can be any data type. List<TItem> is the most common example.
IEnumerable
(System.Collections.IEnumerable)
Summary
Any data type representing a collection of items that can iterated or looped over.
The items contained in the collection can be any data type.
Any data type representing a collection of items that can iterated or looped over. TItem indicates the data type of the items contained in the collection. List<TItem> is the most common example.
IEnumerable<TItem>
(System.Collections.Generic.IEnumerable<TItem>)
Summary
Any data type representing a collection of items that can iterated or looped over.
TItem indicates the data type of the items contained in the collection.
Any data type representing a collection of items that can iterated or looped over. TItem indicates the data type of the items contained in the collection.
Size:
Varies
Default Value:
null
Can be used as:
IEnumerable, Object, dynamic
IEnumerable<TItemBaseType> (e.g. where IEnumerable<TItem> is IEnumerable<Int32> and IEnumerable<TItemBaseType> is IEnumerable<Object> as Object is a base type of Int32; this is called covariance)
Can be cast to:
N/A
Remarks
Most Common IEnumerable<TItem> Data Types
Any of the following data types can be used where an IEnumerable<TItem> is required:
Any data type representing a list of items that can iterated or looped over. TItem indicates the data type of the items contained in the list. Each TItem can be individually accessed by an index. List<TItem> is the most common example.
IList<TItem>
(System.Collections.Generic.IList<TItem>)
Summary
Any data type representing a list of items that can iterated or looped over.
TItem indicates the data type of the items contained in the list. Each TItem can be individually accessed by an index.
List<TItem> is the most common example.
Category:
Collections
Name:
IList<TItem>
Full Name:
System.Collections.Generic.IList<TItem>
Alias:
N/A
Description:
Any data type representing a list of items that can iterated or looped over. TItem indicates the data type of the items contained in the list. Each TItem can be individually accessed by an index.
Size:
Varies
Default Value:
null
Can be used as:
IEnumerable<TItem>, IEnumerable, Object, dynamic
IEnumerable<TItemBaseType> (e.g. where IList<TItem> is IList<Int32> and IEnumerable<TItemBaseType> is IEnumerable<Object> as Object is a base type of Int32; this is called covariance)
Can be cast to:
N/A
Remarks
Most Common IList<TItem> Data Types
Any of the following data types can be used where an IList<TItem> is required:
Used to represent a list of items that can iterated or looped over. TItem indicates the data type of the items contained in the list. Each TItem can be individually accessed by an index.
List<TItem>
(System.Collections.Generic.List<TItem>)
Summary
The List<TItem> data type is used to represent a list of items that can iterated or looped over.
TItem indicates the data type of the items contained in the list. Each TItem can be individually accessed by an index.
Category:
Collections
Name:
List<TItem>
Full Name:
System.Collections.Generic.List<TItem>
Alias:
N/A
Description:
A list of items that can iterated or looped over. TItem indicates the data type of the items contained in the list. Each TItem can be individually accessed by an index.
IEnumerable<TItemBaseType> (e.g. where List<TItem> is List<Int32> and IEnumerable<TItemBaseType> is IEnumerable<Object> as Object is a base type of Int32; this is called covariance)
Can be cast to:
N/A
Remarks
Create a List<TItem>
The following table shows some of the ways that a List<TItem> can be created.
Method
Example
Result
Editor Support
Notes
Declare a List<TItem> literal
[]
[]
Expression
List<dynamic> containing zero items
["Some Text"]
["Some Text"]
Expression
List<String> containing one String item
[true, false]
[true, false]
Expression
List<Boolean> containing two Boolean items
[1, 2, 3]
[1, 2, 3]
Expression
List<Int32> containing three Int32 items
["Some Text", true, 1]
["Some Text", true, 1]
Expression
List<dynamic> containing a String item, a Boolean item and an Int32 item
Use a List<TItem> expression
new List<dynamic>()
[]
Expression
List<dynamic> containing zero items
new List<String>() { "Some Text" }
["Some Text"]
Expression
List<String> containing one String item
new List<Boolean>() { true, false }
[true, false]
Expression
List<Boolean> containing two Boolean items
new List<Int32>() { 1, 2, 3 }
[1, 2, 3]
Expression
List<Int32> containing three Int32 items
new List<dynamic>() { "Some Text", true, 1 }
["Some Text", true, 1]
Expression
List<dynamic> containing a String item, a Boolean item and an Int32 item
Convert List<TItem> to Text
The following table shows some of the ways that a List<TItem> can be converted to text.
Method
Example
Result
Editor Support
Notes
Use Convert Object To Json block
where Object property has a List<dynamic> value of ["Some Text", true, 1]
Used to represent a collection of key/item pairs, where the data type of the keys used to access the items contained in the collection is String and the items contained in the collection can be any data type. Each item can be individually accessed by its String key.
Structure
(Cortex.DataTypes.Dictionaries.Structure)
Summary
The Structure data type is used to represent a collection of key/item pairs.
The data type of the keys used to access the items contained in the collection is String and the items contained in the collection can be any data type. Each item can be individually accessed by its String key.
Category:
Collections
Name:
Structure
Full Name:
Cortex.DataTypes.Dictionaries.Structure
Alias:
N/A
Description:
Used to represent a collection of key/item pairs, where the data type of the keys used to access the items contained in the collection is String and the items contained in the collection can be any data type. Each item can be individually accessed by its String key.
IEnumerable<KeyValuePair<TKey, TItem>> (e.g. where Structure is IDictionary<String, Object> and IEnumerable<KeyValuePair<TKey, TItem>> is IEnumerable<KeyValuePair<String, Object>>)
Can be cast to:
N/A
Remarks
Create a Structure
The following table shows some of the ways that a Structure can be created.
Method
Example
Result
Editor Support
Notes
Declare a Structure literal
{}
{}
Expression
Structure containing zero items
{ "StringKey1": "StringValue" }
{ "StringKey1": "StringValue" }
Expression
Structure containing one String item with a String key
{ "StringKey1": true, "StringKey2": false }
{ "StringKey1": true, "StringKey2": false }
Expression
Structure containing two Boolean items with String keys
The Domain is used to define the domain or server to authenticate with. The value of this property may optionally be encrypted; for more information on how to encrypt this property, see EncryptableText.
Whether or not the Domain is required is dependent on the block being used:
The Username is used to define the user to authenticate as. The value of this property may optionally be encrypted; for more information on how to encrypt this property, see EncryptableText.
The Password is used to define the password of the user to authenticate as. This property is an EncryptedText and so it must be encrypted; for more information on how to encrypt the password, see EncryptedText.
Data types used for working with data sources such as SQL Server.
6.4.5.1 - Command
Defines a single statement that can be run against a data source.
Command
(Cortex.DataTypes.Data.Command)
Summary
A Command data type is used to define a single statement that can be run against a data source. The statement can be parameterised, which is recommended to prevent SQL Injection.
Category:
Data
Name:
Command
Full Name:
Cortex.DataTypes.Data.Command
Alias:
N/A
Description:
Defines a single statement that can be run against a data source.
Default Value:
null
Can be used as:
DataCommand, Object, dynamic
Can be cast to:
N/A
Properties
Command Text
The Command Text is used to define a single statement that will be run against the data source.
Parameters are used to pass information to the statement that will be run against the data source.
It is recommended to always use Parameterised Commands as they prevent SQL Injection attacks by ensuring the parameters are sanitised before the command is executed.
It is recommended to always use parameterised commands as they prevent SQL Injection attacks by ensuring the parameters are sanitised before the command is executed.
The @ symbol denotes a parameter within the CommandText (e.g. "SELECT * FROM Table WHERE Name = @Parameter"). An example of using parameters can be found in Executing Multiple Commands (Safe), whereas, an example of inserting variables into a statement without parameters can be found in Executing Multiple Commands (Unsafe)
The Expression Editor is available for Input properties where the data type is Command.
The Literal Editor is not available for Input properties where the data type is Command.
The Variable Editor is available for Input, InputOutput and Output properties where the data type is Command.
Known limitations
ToString Method always returns the Full Name
Currently, if the ToString() method is used on a Command, then its Full Name will be returned; instead of a representation of the data within the Command.
Holds the information for parsing a command, running multiple query and non query commands against a data source.
Commands
(Cortex.DataTypes.Data.Commands)
Summary
A Commands data type is used to define single or multiple statements that can be run against a data source. Statements can be parameterised, which is recommended to prevent SQL Injection.
Category:
Data
Name:
Commands
Full Name:
Cortex.DataTypes.Data.Commands
Alias:
N/A
Description:
Defines single or multiple statements that can be run against a data source.
Default Value:
null
Can be used as:
DataCommand, Object, dynamic
Can be cast to:
N/A
Properties
Command Text
The Command Text is used to define single or multiple statements that will be run against the data source.
Parameters are used to pass information to the single or multiple statements that will be run against the data source.
It is recommended to always use Parameterised Commands as they prevent SQL Injection attacks by ensuring the parameters are sanitised before the command is executed.
It is recommended to always use parameterised commands as they prevent SQL Injection attacks by ensuring the parameters are sanitised before the command is executed.
The @ symbol denotes a parameter within the CommandText (e.g. "SELECT * FROM Table WHERE Name = @Parameter"). An example of using parameters can be found in Executing Multiple Commands (Safe), whereas, an example of inserting variables into a statement without parameters can be found in Executing Multiple Commands (Unsafe)
The Expression Editor is available for Input properties where the data type is Commands.
The Literal Editor is available for Input properties where the data type is Commands.
The Variable Editor is available for Input, InputOutput and Output properties where the data type is Commands.
Known limitations
ToString Method always returns the Full Name
Currently, if the ToString() method is used on a Commands, then its Full Name will be returned; instead of a representation of the data within the Commands.
Parameters are used to pass information to the command that will be run against the data source.
It is recommended to always use parameterised commands as they prevent SQL Injection attacks by ensuring the parameters are sanitised before the command is executed.
It is recommended to always use parameterised commands as they prevent SQL Injection attacks by ensuring the parameters are sanitised before the command is executed.
The @ symbol denotes a parameter within the CommandText (e.g. "SELECT * FROM Table WHERE Name = @Parameter"). An example of using parameters can be found in Executing Multiple Commands (Safe), whereas, an example of inserting variables into a statement without parameters can be found in Executing Multiple Commands (Unsafe)
Holds the information for running a Non Query command against a data source.
NonQueryCommand
(Cortex.DataTypes.Data.NonQueryCommand)
Summary
A NonQueryCommand data type is used to define single or multiple Non Query Statements that can be run against a data source. Statements can be parameterised, which is recommended to prevent SQL Injection.
Category:
Data
Name:
NonQueryCommand
Full Name:
Cortex.DataTypes.Data.NonQueryCommand
Alias:
N/A
Description:
Defines single or multiple Non Query Statements that can be run against a data source.
Default Value:
null
Can be used as:
DataCommand, Object, dynamic
Can be cast to:
N/A
Properties
Command Text
The Command Text is used to define single or multiple Non Query Statements that will be run against the data source.
Parameters are used to pass information to the Non Query Statements that will be run against the data source.
It is recommended to always use Parameterised Commands as they prevent SQL Injection attacks by ensuring the parameters are sanitised before the command is executed.
It is recommended to always use parameterised commands as they prevent SQL Injection attacks by ensuring the parameters are sanitised before the command is executed.
The @ symbol denotes a parameter within the CommandText (e.g. "INSERT INTO Table (FirstColumn) VALUES (@Parameter)"). An example of using parameters can be found in Executing Multiple Commands (Safe), whereas, an example of inserting variables into a statement without parameters can be found in Executing Multiple Commands (Unsafe)
The Expression Editor is available for Input properties where the data type is NonQueryCommand.
The Literal Editor is available for Input properties where the data type is NonQueryCommand.
The Variable Editor is available for Input, InputOutput and Output properties where the data type is
Known limitations
ToString Method always returns the Full Name
Currently, if the ToString() method is used on a NonQueryCommand, then its Full Name will be returned; instead of a representation of the data within the NonQueryCommand.
A OdbcConnectionDetails can also be created using the Literal Editor by filling in the necessary values for the following properties:
Property
Data Type
Example
Notes
Connection String
EncryptableText
$@"DSN=LocalHost;Driver={ODBC Driver Version}"
The Connection String that is used to connect to an ODBC data source.
Connection Strings
A Connection String must be provided in order to connect to an ODBC data source. The Connection String can be formatted differently depending on the ODBC driver. See ConnectionStrings.com for a list of ODBC connection strings under each specific data source.
Please see Working with Data Sources for a list of other supported data sources (e.g. SQL Server) and how to construct valid connection strings for them.
Property Editor Support
The Expression Editor is available for Input properties where the data type is OdbcConnectionDetails.
The Literal Editor is not available for Input properties where the data type is OdbcConnectionDetails.
The Variable Editor is available for Input, InputOutput and Output properties where the data type is OdbcConnectionDetails.
Known limitations
Currently string values cannot be used as a parameter when connected to an Microsoft Access data source.
Holds the information for running a Query command against a data source.
QueryCommand
(Cortex.DataTypes.Data.QueryCommand)
Summary
A QueryCommand data type is used to define single or multiple Query Statements that can be run against a data source. Statements can be parameterised, which is recommended to prevent SQL Injection.
Category:
Data
Name:
QueryCommand
Full Name:
Cortex.DataTypes.Data.QueryCommand
Alias:
N/A
Description:
Defines single or multiple Query Statements that can be run against a data source.
Default Value:
null
Can be used as:
DataCommand, Object, dynamic
Can be cast to:
N/A
Properties
Command Text
The Command Text is used to define single or multiple Query Statements that will be run against the data source.
Parameters are used to pass information to the Query Statements that will be run against the data source.
It is recommended to always use Parameterised Commands as they prevent SQL Injection attacks by ensuring the parameters are sanitised before the command is executed.
It is recommended to always use parameterised commands as they prevent SQL Injection attacks by ensuring the parameters are sanitised before the command is executed.
The @ symbol denotes a parameter within the CommandText (e.g. "SELECT * FROM Table WHERE Name = @Parameter"). An example of using parameters can be found in Executing Multiple Commands (Safe), whereas, an example of inserting variables into a statement without parameters can be found in Executing Multiple Commands (Unsafe)
The Expression Editor is available for Input properties where the data type is QueryCommand.
The Literal Editor is available for Input properties where the data type is QueryCommand.
The Variable Editor is available for Input, InputOutput and Output properties where the data type is QueryCommand.
Known limitations
ToString Method always returns the Full Name
Currently, if the ToString() method is used on a QueryCommand, then its Full Name will be returned; instead of a representation of the data within the QueryCommand.
The Connection String that is used to connect to the data source.
Connection Strings
A Connection String must be provided in order to connect to a SQL Server data source. The Connection String can be formatted differently depending either on the version of SQL Server or the way the connection will be created and maintained (e.g. Trusted connection vs explicit user). See ConnectionStrings.com for a list of connection strings for SQL Server.
Please see Working with Data Sources for a list of other supported data sources (e.g. ODBC) and how to construct valid connection strings for them.
Property Editor Support
The Expression Editor is available for Input properties where the data type is SqlServerConnectionDetails.
The Literal Editor is not available for Input properties where the data type is SqlServerConnectionDetails.
The Variable Editor is available for Input, InputOutput and Output properties where the data type is SqlServerConnectionDetails.
Used to represent a date and time between 00:00:00.0000000 UTC, January 1, 0001 and 23:59:59.9999999 UTC, December 31, 9999, in the Gregorian calendar. It can be used wherever a DateTimeOffset is expected, and will be implicitly cast.
DateTime
(System.DateTime)
Summary
The DateTime data type is used to represent a date and time between 00:00:00.0000000 UTC, January 1, 0001 and 23:59:59.9999999 UTC, December 31, 9999, in the Gregorian calendar. It can be used wherever a DateTimeOffset is expected, and will be implicitly cast.
Category:
Date & Time
Name:
DateTime
Full Name:
System.DateTime
Alias:
N/A
Description:
A date and time between 00:00:00.0000000 UTC, January 1, 0001 and 23:59:59.9999999 UTC, December 31, 9999, in the Gregorian calendar. It can be used wherever a DateTimeOffset is expected, and will be implicitly cast.
The following table shows some of the ways that a DateTime can be created.
All examples are for a system configured with British culture (i.e. en-GB), and use a local time of 2PM 1st of July 2022 with 1 hour UTC offset, honouring British Summer Time (BST).
Method
Example
Result
Editor Support
Notes
Use DateTime.Now
DateTime.Now
2022-07-01T14:00:00.0000000+01:00
Expression
The result shown is an example result. The actual result will show the current date and time on the current computer expressed as local time. See DateTime.Now
Use DateTime.UtcNow
DateTime.UtcNow
2022-07-01T13:00:00.0000000Z
Expression
The result shown is an example result. The actual result will show the current date and time on the current computer expressed as the Coordinated Universal Time (UTC). See DateTime.UtcNow
Use DateTime.Parse
DateTime.Parse("1/7/2022 2:00:00 PM")
2022-07-01T14:00:00
Expression
Parses a date string and converts it to a DateTime using the current culture of the system. In this example it parses "1/7/2022 2:00:00 PM" using en-GBculture and converts it to 2022-07-01T14:00:00. See DateTime.Parse
Use a DateTime constructor
new DateTime(2022, 7, 1, 14, 0, 0, 0)
2022-07-01T14:00:00
Expression
2PM 1st July 2022 with 1 hour UTC offset, honouring British Summer Time (BST). See DateTime Constructors.
Use DateTimeOffset.DateTime
DateTimeOffset.UtcNow.DateTime
2022-07-01T13:00:00.0000000
Expression
Converts DateTimeOffset.UtcNow to a DateTime using the date and time components, but not the offset. See DateTimeOffset.DateTime
The following table shows some of the ways that a DateTime can be converted to text.
All examples are for a system configured with British culture (i.e. en-GB), and use a local time of 2PM 1st of July 2022 with 1 hour UTC offset, honouring British Summer Time (BST).
Method
Example
Result
Editor Support
Notes
Use ToString
DateTime.UtcNow.ToString()
"1/7/2022 1:00:00 PM"
Expression
The result shown is an example result. The actual result will show the current date and time on the current computer expressed as the Coordinated Universal Time (UTC) converted to text. Both the example and actual result will use the short date pattern for the current culture and the long time pattern for the current culture with each element separated from the previous element by a space. See DateTime.ToString
Use Convert.ToString
Convert.ToString(DateTime.UtcNow)
"1/7/2022 1:00:00 PM"
Expression
The result shown is an example result. The actual result will show the current date and time on the current computer expressed as the Coordinated Universal Time (UTC) converted to text. Both the example and actual result will use the short date pattern for the current culture and the long time pattern for the current culture, with each element separated from the previous element by a space. See Convert.ToString
Use Convert DateTime To Text block
where Date Time property has a value of DateTime.UtcNow
"2022-07-01T13:00:00.0000000+00:00"
Expression
The result shown is an example result. The actual result will show the current date and time on the current computer expressed as the Coordinated Universal Time (UTC) converted to text. Both the example and actual result will use ISO 8601 Standard format for DateTimeOffset (i.e. yyyy-MM-ddTHH:mm:ss.fffffffzzz) as the Convert DateTime To Text block will impicitly convert a DateTime to a DateTimeOffset. See Convert DateTime To Text
Use Convert Object To Text block
where Object property has a value of DateTime.UtcNow
"1/7/2022 1:00:00 PM"
Expression
The result shown is an example result. The actual result will show the current date and time on the current computer expressed as the Coordinated Universal Time (UTC) converted to text. Both the example and actual result will use the short date pattern for the current culture and the long time pattern for the current culture, with each element separated from the previous element by a space. See Convert Object To Text
Use Convert Object To Json block
where Object property has a value of DateTime.UtcNow
"\"2022-07-01T13:00:00.0000000Z\""
Expression
The result shown is an example result. The actual result will show the current date and time on the current computer expressed as the Coordinated Universal Time (UTC) converted to text. Both the example and actual result will use ISO 8601 Standard format for DateTime (i.e. yyyy-MM-ddTHH:mm:ss.fffffffK). See Convert Object To Json
Used to represent a date and time between 00:00:00.0000000 UTC, January 1, 0001 and 23:59:59.9999999 UTC, December 31, 9999, in the Gregorian calendar, along with a UTC time offset.
DateTimeOffset
(System.DateTimeOffset)
Summary
The DateTimeOffset data type is used to represent a date and time between 00:00:00.0000000 UTC, January 1, 0001 and 23:59:59.9999999 UTC, December 31, 9999, in the Gregorian calendar, along with a UTC time offset.
Category:
Date & Time
Name:
DateTimeOffset
Full Name:
System.DateTimeOffset
Alias:
N/A
Description:
A date and time between 00:00:00.0000000 UTC, January 1, 0001 and 23:59:59.9999999 UTC, December 31, 9999, in the Gregorian calendar, along with a UTC time offset.
The following table shows some of the ways that a DateTimeOffset can be created.
All examples are for a system configured with British culture (i.e. en-GB), and use a local time of 2PM 1st of July 2022 with 1 hour UTC offset, honouring British Summer Time (BST).
Method
Example
Result
Editor Support
Notes
Use DateTimeOffset.Now
DateTimeOffset.Now
2022-07-01T14:00:00.0000000+01:00
Expression
The result shown is an example result. The actual result will show the current date and time on the current computer, with the offset set to the local time’s offset from Coordinated Universal Time (UTC). See DateTimeOffset.Now.
Use DateTimeOffset.UtcNow
DateTimeOffset.UtcNow
2022-07-01T13:00:00.0000000+00:00
Expression
The result shown is an example result. The actual result will show the current Coordinated Universal Time (UTC) date and time and whose offset is Zero. See DateTimeOffset.UtcNow.
The result shown is an example result. The actual result will show the current Coordinated Universal Time (UTC) date and time and whose offset is Zero.
Use DateTimeOffset.Parse
DateTimeOffset.Parse("1/7/2022 2:00:00 PM +1:00")
2022-07-01T14:00:00+01:00
Expression
Parses a date string and converts it to a DateTimeOffset using the current culture of the system. In this example it parses "1/7/2022 2:00:00 PM +1:00" using en-GBculture and converts it to 2022-07-01T14:00:00+01:00. See DateTimeOffset.Parse
Use a DateTimeOffset constructor
new DateTimeOffset(2022, 7, 1, 14, 0, 0, 0, new TimeSpan(1, 0, 0))
2022-07-01T14:00:00+01:00
Expression
2PM 1st July 2022 with 1 hour UTC offset, honouring British Summer Time (BST). See DateTimeOffset Constructors.
Use Convert Text To DateTime block
where Text property has a value of "1/7/2022 2:00:00 PM +1:00"
A DateTimeOffset can also be created using the Literal Editor by filling in the necessary values for the following properties:
Property
Data Type
Notes
Year
Int32
The year expressed as an Int32 value between 1 and 9999.
Month
Int32
The month expressed as an Int32 value between 1 and 12.
Day
Int32
The day expressed as an Int32 value between 1 and the number of days in Month.
Hour
Int32
The hour expressed as an Int32 value between 0 and 23.
Minute
Int32
The minute expressed as an Int32 value between 0 and 59.
Second
Int32
The second expressed as an Int32 value between 0 and 59.
Millisecond
Int32
The millisecond expressed as an Int32 value between 0 and 999.
Offset
TimeSpan
The UTC Offset expressed as a TimeSpan value between -14 hours and 14 hours. This is calculated as the sum of Offset.Days + Offset.Hours + Offset.Minutes + Offset.Seconds + Offset.Milliseconds. If the value is outside -14 hours and 14 hours an InvalidPropertyValueException will be thrown.
Convert DateTimeOffset to Text
The following table shows some of the ways that a DateTimeOffset can be converted to text.
All examples are for a system configured with British culture (i.e. en-GB), and use a local time of 2PM 1st of July 2022 with 1 hour UTC offset, honouring British Summer Time (BST).
Method
Example
Result
Editor Support
Notes
Use ToString
DateTimeOffset.UtcNow.ToString()
"1/7/2022 1:00:00 PM +00:00"
Expression
The result shown is an example result. The actual result will show the current Coordinated Universal Time (UTC) date and time and whose offset is Zero converted to text. Both the example and actual result will use the short date pattern for the current culture, the long time pattern for the current culture, and the zzzcustom format string, with each element separated from the previous element by a space. See DateTimeOffset.ToString
Use Convert.ToString
Convert.ToString(DateTimeOffset.UtcNow)
"1/7/2022 1:00:00 PM +00:00"
Expression
The result shown is an example result. The actual result will show the current Coordinated Universal Time (UTC) date and time and whose offset is Zero converted to text. Both the example and actual result will use the short date pattern for the current culture, the long time pattern for the current culture, and the zzzcustom format string, with each element separated from the previous element by a space. See Convert.ToString
Use Convert DateTime To Text block
where Date Time property has a value of DateTimeOffset.UtcNow
"2022-07-01T13:00:00.0000000+00:00"
Expression
The result shown is an example result. The actual result will show the current Coordinated Universal Time (UTC) date and time and whose offset is Zero converted to text. Both the example and actual result will use ISO 8601 Standard format for DateTimeOffset (i.e. yyyy-MM-ddTHH:mm:ss.fffffffzzz). See Convert DateTime To Text
Use Convert Object To Text block
where Object property has a value of DateTimeOffset.UtcNow
"1/7/2022 1:00:00 PM +00:00"
Expression
The result shown is an example result. The actual result will show the current Coordinated Universal Time (UTC) date and time and whose offset is Zero converted to text. Both the example and actual result will use the short date pattern for the current culture, the long time pattern for the current culture, and the zzzcustom format string, with each element separated from the previous element by a space. See Convert Object To Text
Use Convert Object To Json block
where Object property has a value of DateTimeOffset.UtcNow
"\"2022-07-01T13:00:00.0000000+00:00\""
Expression
The result shown is an example result. The actual result will show the current Coordinated Universal Time (UTC) date and time and whose offset is Zero converted to text. Both the example and actual result will use ISO 8601 Standard format for DateTimeOffset (i.e. yyyy-MM-ddTHH:mm:ss.fffffffzzz). See Convert Object To Json
The following table shows some of the ways that a DateTimeOffset can be converted to a DateTime.
All examples are for a system configured with British culture (i.e. en-GB), and use a local time of 2PM 1st of July 2022 with 1 hour UTC offset, honouring British Summer Time (BST).
Method
Example
Result
Editor Support
Notes
Use DateTimeOffset.DateTime
DateTimeOffset.UtcNow.DateTime
2022-07-01T13:00:00.0000000
Expression
Converts DateTimeOffset.UtcNow to a DateTime using the date and time components, but not the offset. See DateTimeOffset.DateTime
Used to represent a time interval (duration of time or elapsed time) that is measured as a positive or negative number of years, months, days, hours, minutes, seconds, and milliseconds.
TimePeriod
(Cortex.DataTypes.DateAndTime.TimePeriod)
Summary
Properties
Years
Months
Days
Hours
Minutes
Seconds
Milliseconds
Remarks
Create a TimePeriod
Convert TimePeriod to Text
Property Editor Support
Known Limitations
See Also
Related Data Types
Related Concepts
External Documentation
6.4.6.6 - TimeSpan
Used to represent a time interval (duration of time or elapsed time) that is measured as a positive or negative number of days, hours, minutes, seconds, and milliseconds. It can be used wherever a TimePeriod is expected, and wll be converted to a TimePeriod automatically.
TimeSpan
(System.TimeSpan)
Summary
Remarks
Create a TimeSpan
Convert TimeSpan to Text
Property Editor Support
Known Limitations
See Also
Related Data Types
Related Concepts
External Documentation
6.4.7 - Email
Data types used for working with emails and connecting to mail servers.
6.4.7.1 - Authentication
Data types used for authenticating with mail servers.
6.4.7.1.1 - EmailCredentials
Used to represent details required to authenticate with a mail server.
The following table shows some of the ways that BasicEmailSessionDetails can be created.
Method
Example
Result
Editor Support
Notes
Use a BasicEmailSessionDetails constructor
new BasicEmailSessionDetails(serverDetails: new ServerDetails("smtp.gmail.com", 465, true), credentials: new UserCredentials("sender@gmail.com", "encryptedPassword"))
where Object property has a value of {"ServerDetails": {"Host": "smtp.gmail.com", "Port": 465, "UseSsl": true}, "Credentials": {"Domain": null, "Username": "sender@gmail.com", "Password": "encryptedPassword"}}
new EmailMessage(to: new List<EmailAddress>(){ new EmailAddress("recipient@outlook.com") }, from: new EmailAddress("sender@outlook.com"), cc: new List<EmailAddress>(){ new EmailAddress("cc@outlook.com") }, bcc: new List<EmailAddress>(){ new EmailAddress("bcc@outlook.com") }, priority: EmailMessagePriority.Urgent, subject: "Example email subject", bodyFormat: EmailMessageBodyFormat.Text, body: "Example email body", attachments: new List<string>(){ @"C:\attachment.txt" })
Used to represent the format of an email message body.
EmailMessageBodyFormat
(Cortex.DataTypes.Email.EmailMessageBodyFormat)
Summary
The EmailMessageBodyFormat data type is used to represent the format of an email message body.
EmailMessageBodyFormat is an enum data type, which means it has a defined set of values, where each value has an associated String name and Int32 value.
Category:
Email
Name:
EmailMessageBodyFormat
Full Name:
Cortex.DataTypes.Email.EmailMessageBodyFormat
Alias:
N/A
Description:
Format of an email message body.
Size:
4 bytes
Default Value:
EmailMessageBodyFormat.Text
Can be used as:
EmailMessageBodyFormat, Object, dynamic
Can be cast to:
Int16 (e.g. (Int16)EmailMessageBodyFormat.Text or (System.Int16)EmailMessageBodyFormat.Text or (short)EmailMessageBodyFormat.Text)
Int32 (e.g. (Int32)EmailMessageBodyFormat.Text or (System.Int32)EmailMessageBodyFormat.Text or (int)EmailMessageBodyFormat.Text)
Int64 (e.g. (Int64)EmailMessageBodyFormat.Text or (System.Int64)EmailMessageBodyFormat.Text or (long)EmailMessageBodyFormat.Text)
Single (e.g. (Single)EmailMessageBodyFormat.Text or (System.Single)EmailMessageBodyFormat.Text or (float)EmailMessageBodyFormat.Text)
Double (e.g. (Double)EmailMessageBodyFormat.Text or (System.Double)EmailMessageBodyFormat.Text or (double)EmailMessageBodyFormat.Text)
Used to represent an error code explaining the reason an EmailSessionException occurred.
EmailSessionErrorCode
(Cortex.DataTypes.Email.EmailSessionErrorCode)
Summary
The EmailSessionErrorCode data type is used to represent an error code explaining the reason an EmailSessionException occurred. For more information on the exception itself, see EmailSessionException.
EmailSessionErrorCode is an enum data type, which means it has a defined set of values, where each value has an associated String name and Int32 value.
Int16 (e.g. (Int16)EmailSessionErrorCode.InvalidPort or (System.Int16)EmailSessionErrorCode.InvalidPort or (short)EmailSessionErrorCode.InvalidPort)
Int32 (e.g. (Int32)EmailSessionErrorCode.InvalidPort or (System.Int32)EmailSessionErrorCode.InvalidPort or (int)EmailSessionErrorCode.InvalidPort)
Int64 (e.g. (Int64)EmailSessionErrorCode.InvalidPort or (System.Int64)EmailSessionErrorCode.InvalidPort or (long)EmailSessionErrorCode.InvalidPort)
Single (e.g. (Single)EmailSessionErrorCode.InvalidPort or (System.Single)EmailSessionErrorCode.InvalidPort or (float)EmailSessionErrorCode.InvalidPort)
Double (e.g. (Double)EmailSessionErrorCode.InvalidPort or (System.Double)EmailSessionErrorCode.InvalidPort or (double)EmailSessionErrorCode.InvalidPort)
Converts EmailSessionErrorCode.InvalidGmailClientCredentials to 401. See Convert.ToInt32
Property Editor Support
The Expression Editor is available for Input properties where the data type is EmailSessionErrorCode.
The Literal Editor is available for Input properties where the data type is EmailSessionErrorCode.
The Variable Editor is available for Input, InputOutput and Output properties where the data type is EmailSessionErrorCode.
Known Limitations
Currently for the SslUnsupported error code, there are numerous reasons for why the exception may have occurred. For more information, see SSL Unsupported.
No value (defaults to 00000000-0000-0000-0000-000000000000)
Remarks
Create a FlowReference
Currently a FlowReference can only created by using the Flow Property of the Run Flow block. Using the editor to select a flow (by its Name or Id) will create a flow reference for the block to use.
Property Editor Support
The Expression Editor is not available for Input, InputOutput and Output properties where the data type is FlowReference.
The Literal Editor is available for Input properties where the data type is FlowReference.
The Variable Editor is available for Output properties where the data type is FlowReference.
IEnumerable<KeyValuePair<TKey, TItem>> (e.g. where InputVariables is IDictionary<String, Object> and IEnumerable<KeyValuePair<TKey, TItem>> is IEnumerable<KeyValuePair<String, Object>>)
Can be cast to:
N/A
Remarks
Create an InputVariables
The following table shows some of the ways that an InputVariables can be created.
Method
Example
Result
Editor Support
Notes
Use an InputVariables expression
new InputVariables()
{}
Expression
InputVariables containing zero items
new InputVariables() { { "Variable1", true } }
{ "Variable1": true }
Expression
InputVariables containing one Boolean item with a String key
InputVariables containing Boolean and Int32 items with String keys
An InputVariables can also be created using the Literal Editor when using the Run Flow block. For more information see the Inputs Property of the Run Flow block.
Property Editor Support
The Expression Editor is available for Input properties where the data type is InputVariables.
The Literal Editor is available for Input properties where the data type is InputVariables.
The Variable Editor is available for Input, InputOutput and Output properties where the data type is InputVariables.
Used to specify settings for converting objects to and from Json.
JsonSerializerSettings
(Newtonsoft.Json.JsonSerializerSettings)
Summary
Remarks
Create a JsonSerializerSettings
Convert JsonSerializerSettings to Text
Property Editor Support
Known Limitations
See Also
Related Data Types
Related Concepts
External Documentation
TODO:
Need to have a link to default settings and explain that convert object to json sets formatting.indented
6.4.14 - Logs
Data types used for working with logs.
6.4.14.1 - EventSeverity
Used to represent the severity of an event when it is logged.
EventSeverity
(Cortex.DataTypes.Logs.EventSeverity)
Summary
Values
Verbose
Debug
Information
Warning
Error
Fatal
Remarks
Create an EventSeverity
Convert EventSeverity to Text
Property Editor Support
Known Limitations
See Also
Related Data Types
Related Concepts
External Documentation
6.4.15 - Loops
Data types used for working with loops.
6.4.15.1 - InfiniteLoopErrorCode
Used to represent an error code explaining the reason an InfiniteLoopException occurred.
InfiniteLoopErrorCode
(Cortex.DataTypes.Loops.InfiniteLoopErrorCode)
Summary
Values
IncrementIsZero
IncrementIsNegative
IncrementIsPositive
Remarks
Create an InfiniteLoopErrorCode
Convert InfiniteLoopErrorCode to Text
Property Editor Support
Known Limitations
See Also
Related Data Types
Related Concepts
External Documentation
6.4.16 - Numbers
Data types used for working with numbers.
6.4.16.1 - Double
Used to represent a fractional, or very large or small number from -1.79769313486232e+308 through 1.79769313486232e+308.
Double
(System.Double)
Summary
The Double data type is used to represent a fractional, or very large or small number from -1.79769313486232e+308 through 1.79769313486232e+308.
Category:
Numbers
Name:
Double
Full Name:
System.Double
Alias:
double
Description:
A fractional, or very large or small number from -1.79769313486232e+308 through 1.79769313486232e+308
Size:
8 bytes
Default Value:
0
Can be used as:
Object, dynamic
Can be cast to:
Int16, as long as value is from -32,768 through 32,767 (e.g. (Int16)32767 or (System.Int16)32767 or (short)32767)
Int32, as long as value is from -2,147,483,648 through 2,147,483,647 (e.g. (Int32)2147483647 or (System.Int32)2147483647 or (int)2147483647)
Int64, as long as value is from -9,223,372,036,854,775,808 through 9,223,372,036,854,775,807 (e.g. (Int64)9223372036854775807 or (System.Int64)9223372036854775807 or (long)9223372036854775807)
Single, as long as value is from -3.402823e+38 through 3.402823e+38 (e.g. (Single)3.402823e+38 or (System.Single)3.402823e+38 or (float)3.402823e+38)
Remarks
Create a Double
The following table shows some of the ways that a Double can be created.
Used to represent a whole number from -9,223,372,036,854,775,808 through 9,223,372,036,854,775,807.
Int64
(System.Int64)
Summary
The Int64 data type is used to represent a whole number from -9,223,372,036,854,775,808 through 9,223,372,036,854,775,807.
Category:
Numbers
Name:
Int64
Full Name:
System.Int64
Alias:
long
Description:
A whole number from -9,223,372,036,854,775,808 through 9,223,372,036,854,775,807
Size:
8 bytes
Default Value:
0
Can be used as:
Int64, Single, Double, Object, dynamic
Can be cast to:
Int16, as long as value is from -32,768 through 32,767 (e.g. (Int16)32767 or (System.Int16)32767 or (short)32767)
Int32, as long as value is from -2,147,483,648 through 2,147,483,647 (e.g. (Int32)2147483647 or (System.Int32)2147483647 or (int)2147483647)
Remarks
Create an Int64
The following table shows some of the ways that an Int64 can be created.
Method
Example
Result
Editor Support
Notes
Declare an Int64 literal
9223372036854775807
9223372036854775807
Literal, Expression
Positive, where value is greater than 2,147,483,647. If it is between 0 and 2,147,483,647 it will only be an Int64 if the property’s data type is also Int64, otherwise it will be an Int32.
-9223372036854775808
-9223372036854775808
Literal, Expression
Negative, where value is less than -2,147,483,648. If it is between -2,147,483,648 and 0 it will only be an Int64 if the property’s data type is also Int64, otherwise it will be an Int32.
Used to represent a fractional, or very large or small number from -3.402823e+38 through 3.402823e+38.
Single
(System.Single)
Summary
The Single data type is used to represent a fractional, or very large or small number from -3.402823e+38 through 3.402823e+38.
Category:
Numbers
Name:
Single
Full Name:
System.Single
Alias:
float
Description:
A fractional, or very large or small number from -3.402823e+38 through 3.402823e+38
Size:
4 bytes
Default Value:
0
Can be used as:
Double, Object, dynamic
Can be cast to:
Int16, as long as value is from -32,768 through 32,767 (e.g. (Int16)32767 or (System.Int16)32767 or (short)32767)
Int32, as long as value is from -2,147,483,648 through 2,147,483,647 (e.g. (Int32)2147483647 or (System.Int32)2147483647 or (int)2147483647)
Int64, as long as value is from -9,223,372,036,854,775,808 through 9,223,372,036,854,775,807 (e.g. (Int64)9223372036854775807 or (System.Int64)9223372036854775807 or (long)9223372036854775807)
Remarks
Create a Single
The following table shows some of the ways that a Single can be created.
Used to represent details required to connect to a server.
ServerDetails
(Cortex.DataTypes.SessionDetails.ServerDetails)
Summary
The ServerDetails data type is used to represent details required to connect to a server.
Category:
Session Details
Name:
ServerDetails
Full Name:
Cortex.DataTypes.SessionDetails.ServerDetails
Alias:
N/A
Description:
Details required to connect to a server.
Default Value:
null
Can be used as:
ServerDetails, Object, dynamic
Can be cast to:
N/A
Properties
Host
The Host is used to define the address of the server to connect to. The value of this property may optionally be encrypted; for more information on how to encrypt this property, see EncryptableText.
A server address can typically be represented in one of the following formats:
Fully Qualified Domain Name (e.g. "smtp.gmail.com")
Machine name (e.g. "mail-server1")
IP address (e.g. "127.0.0.1")
Localhost (e.g. "localhost")
The server address formats supported are dependent on the block being used:
Used to represent information about a specific culture, including the names for the culture, the writing system, the calendar used, the sort order of strings, and formatting for dates and numbers.
CultureInfo
(System.Globalization.CultureInfo)
Summary
Remarks
Create a CultureInfo
Convert CultureInfo to Text
Property Editor Support
Known Limitations
See Also
Related Data Types
Related Concepts
External Documentation
TODO:
If the culture identifier is empty e.g (new CultureInfo("")), cultureInfo is set to InvariantCulture.
If the culture does not exist, the operating system will create a custom culture using the culture identifier.
As well as the default InvariantCulture you can also use the culture of the system (CultureInfo.CurrentCulture) or provide a new culture info (new CultureInfo(“en-GB”)).
Note about formatProvider and CultureInfo: If an invalid CultureInfo is provided (e.g. new CultureInfo(“enaa”)), a CultureNotFoundException will be thrown.
Talk about CultureInfo.InvariantCulture
Talk about CultureInfo.CurrentCulture
6.4.19.3 - Encoding
The data type that all encodings inherit from. An encoding is used to represent a specific character encoding (e.g. ASCII, UTF8, Unicode).
Encoding
(System.Text.Encoding)
Summary
Remarks
Create an Encoding
Convert Encoding to Text
Property Editor Support
Known Limitations
See Also
Related Data Types
Related Concepts
External Documentation
6.4.19.4 - EncryptableText
Used to represent text that can be, but does not need to be encrypted.
EncryptableText
(Cortex.DataTypes.Text.EncryptableText)
Summary
Remarks
Create an EncryptableText
Convert EncryptableText to Text
Property Editor Support
Known Limitations
See Also
Related Data Types
Related Concepts
External Documentation
6.4.19.5 - EncryptedText
Used to represent text that must be encrypted.
EncryptedText
(Cortex.DataTypes.Text.EncryptedText)
Summary
Remarks
Create an EncryptedText
Convert EncryptedText to Text
Property Editor Support
Known Limitations
See Also
Related Data Types
Related Concepts
External Documentation
6.4.19.6 - IFormatProvider
The data type providing the contract that all data types that control formatting must implement.
IFormatProvider
(System.IFormatProvider)
Summary
Remarks
Create a data type that implements IFormatProvider
Convert IFormatProvider to Text
Property Editor Support
Known Limitations
See Also
Related Data Types
Related Concepts
External Documentation
6.4.19.7 - SearchOptions
Used to define how text searches determine whether text matches the search (i.e. text contains the searched for text or matches the specified regex or pattern).
SearchOptions
(Cortex.DataTypes.Text.SearchOptions)
Summary
Values
ContainsText
Regex
PatternMatching
Remarks
Create SearchOptions
Convert SearchOptions to Text
Property Editor Support
Known Limitations
See Also
Related Data Types
Related Concepts
External Documentation
6.4.19.8 - String
Used to represent text.
String
(System.String)
Summary
The String data type is used to represent text.
Category:
Text
Name:
String
Full Name:
System.String
Alias:
string
Description:
A sequence of unicode characters, surrounded by double quotes (e.g. "This is a string")
Size:
Varies depending upon the number of characters it contains
Default Value:
null
Can be used as:
IEnumerable, IEnumerable<Char>, Object, dynamic
Can be cast to:
N/A
Remarks
Create a String
The following table shows some of the ways that a String can be created.
Method
Example
Result
Editor Support
Notes
Declare a String literal
"Hello World!"
"Hello World!"
Literal, Expression
In the Expression Editor the surrounding double quotes (i.e. "") are needed (e.g. "Hello World!"); in the Literal Editor they are not (e.g. Hello World!). Any double quotes in the Literal Editor will be treated as literal characters that are part of the String.
Use a String expression
$"Hello {($)Variable}!" where ($)Variable is set to "World!"
"Hello World!"
Expression
Uses [String Interpolation][]
String.Format("Hello {0}!", ($)Variable) where ($)Variable is set to "World!"
The exception thrown when a property is provided with a value that contains at least one item that is either null or empty, but the item is required to have a value.
The exception thrown when a property is provided with a value that contains at least one item that is either null or empty, but the item is required to have a value.
Reasons
Value Contains null or empty item
A null or empty item is contained in the value that was provided for the property.
"'<property-name>' contains at least one null or empty value; it must only contain values that are not null or empty.
Please click the HelpLink for more information on how to fix this."
where:
<property-name> is the name of the property.
How to fix
Ensure the value provided for the property named <property-name> does not contain items that are either null or empty.
Properties
Exception Type
The type of the exception (i.e. PropertyContainsNullOrEmptyItemException).
Currently, only the <property-name> has been included in the exception. In future, we will look to include the name and Id of the block, the id, name and value of the property, as well as allowing the exception to contain a link to take you directly to the offending value.
Currently, only the <property-name> has been included in the exception. In future, we will look to include the name and Id of the block, the id, name and value of the property, as well as allowing the exception to contain a link to take you directly to the offending value.
"Invalid '<second-property-name>' provided.
There are <items-in-second-property> items in '<second-property-name>' and <items-in-first-property> items in '<first-property-name>'.
The number of items in '<second-property-name>' must be the same as the number of items in '<first-property-name>'.
Please click the HelpLink for more information on how to fix this."
where:
<first-property-name> is the name of the first property.
<second-property-name> is the name of the second property.
<items-in-first-property> is the count of items in the first property.
<items-in-second-property> is the count of items in the second property.
How to fix
Ensure that the value provided for each of the two properties contains the same number of items.
Properties
Exception Type
The type of the exception (i.e. PropertyItemCountException).
Currently, the <first-property-name> and <second-property-name> have been included in the exception. In future, we will look to include the name and Id of the block, the id, name and value of the property, as well as allowing the exception to contain a link to take you directly to the offending value.
Currently, only the <property-name> has been included in the exception. In future, we will look to include the name and Id of the block, the id, name and value of the property, as well as allowing the exception to contain a link to take you directly to the offending value.
"Invalid '<property-name>' provided.
There are no items in '<collection-property-name>'.
Check that '<collection-property-name>' is not empty.
Please click the HelpLink for more information on how to fix this."
where:
<collection-property-name> is the name of the empty collection property.
<property-name> is the name of another property used to perform the get, set or remove operation (e.g. index, indexes, count etc.).
"Invalid '<property-name>' provided.
Check that '<property-name>' is not null or empty.
Please click the HelpLink for more information on how to fix this."
where:
<property-name> is the name of the null or empty (i.e. "") text property.
The format of the Message can be one of the following:
"'<property-name>' given was <invalid-value>; it must be a value between <minimum-allowed-value> and <maximum-allowed-value>.
Please click the HelpLink for more information on how to fix this."
or
"'<property-name>' given was <invalid-value>; it must be a value between <minimum-allowed-value> and <maximum-allowed-value> (<calculation-of-maximum-allowed-value>).
Please click the HelpLink for more information on how to fix this."
or
"'<related-property-name>' given was <related-property-value> and '<property-name>' given was <invalid-value>.
The '<property-name>' must be less than or equal to <maximum-allowed-value> (<calculation-of-maximum-allowed-value>).
Please click the HelpLink for more information on how to fix this."
or
"Invalid '<property-name>' provided.
The values <invalid-value> in '<property-name>' are outside of the expected range.
Check that the provided values of '<property-name>' are between <minimum-allowed-value> and <maximum-allowed-value>.
Please click the HelpLink for more information on how to fix this."
where:
<property-name> is the name of the property with the invalid value (e.g. Length, Count, Index).
<invalid-value> is the invalid value of the property (e.g. 100 for non-collection values or 100, 200 for collection values).
<minimum-allowed-value> is the minimum value allowed (e.g. 0).
<maximum-allowed-value> is the maximum value allowed (e.g. 9).
<calculation-of-maximum-allowed-value> is how the maximum allowed value is calculated (e.g. 'Text.Length' - 1).
<related-property-name> is the name of a related property relevant to the exception (e.g. Index).
<related-property-value> is the value of a related property relevant to the exception (e.g. 1).
How to fix
Provide a valid value for the property as instructed by the Message.
"The provided 'TimePeriod' (<time-period-value-as-text>) equates to <time-period-value-as-milliseconds> milliseconds which is invalid; it must be a non-negative value.
Please click the HelpLink for more information on how to fix this."
where:
<time-period-value-as-text> is the TimePeriod value in its text representation (e.g. 0.0.0.0:0:0:-10).
<time-period-value-as-milliseconds> is the TimePeriod value represented as total milliseconds (e.g. -10).
"The provided 'DateTimeOffset' (<value-of-date-time-offset-property>) with the addition of the given 'TimePeriod' (<value-of-time-period-property>) is greater than the maximum of a DateTimeOffset (<maximum-value-of-date-time-offset>).
Please click the HelpLink for more information on how to fix this."
"The provided 'DateTimeOffset' (<value-of-date-time-offset-property>) with the subtraction of the given 'TimePeriod' (<value-of-time-period-property>) is greater than the maximum of a DateTimeOffset (<maximum-value-of-date-time-offset>).
Please click the HelpLink for more information on how to fix this."
where:
<value-of-date-time-property> is the value of the DateTimeOffset in ISO 8601 format (i.e. 2022-07-01T14:00:00.0000000+01:00).
<value-of-time-period-property> is the value of the TimePeriod in text format (i.e. 9999.0.0.0:0:0:0).
<maximum-value-of-date-time-offset> is the maximum value of a DateTimeOffset (i.e. 9999-12-31T23:59:59.9999999+00:00).
How to fix
Provide a TimePeriod value that when added to or subtracted from the property results in the property being less than the allowed maximum value of the DateTimeOffset data type.
"The provided 'DateTimeOffset' (<value-of-date-time-offset-property>) with the subtraction of the given 'TimePeriod' (<value-of-time-period-property>) is less than the minimum of a DateTimeOffset (<minimum-value-of-date-time-offset>).
Please click the HelpLink for more information on how to fix this."
"The provided 'DateTimeOffset' (<value-of-date-time-offset-property>) with the addition of the given 'TimePeriod' (<value-of-time-period-property>) is less than the minimum of a DateTimeOffset (<minimum-value-of-date-time-offset>).
Please click the HelpLink for more information on how to fix this."
where:
<value-of-date-time-property> is the value of the DateTimeOffset in ISO 8601 format (i.e. 2022-07-01T14:00:00.0000000+01:00).
<value-of-time-period-property> is the value of the TimePeriod in text format (i.e. -9999.0.0.0:0:0:0).
<minimum-value-of-date-time-offset> is the minimum value of a DateTimeOffset (i.e. 0001-01-01T00:00:00.0000000+00:00).
How to fix
Provide a TimePeriod value that when added to or subtracted from the property results in the property being greater than the allowed minimum value of the DateTimeOffset data type.
Properties
Exception Type
The type of the exception (i.e. PropertyValueOutOfRangeException).
The exception thrown when trying to modify a read-only dictionary.
Dictionaries implementing IDictionary<TKey, TItem> have the option to be read-only.
The format of the exception message is as follows:
"'<property-display-name>' cannot be because it's read-only.
Please click the HelpLink for more information on how to fix this."
How to fix
If the dictionary was written directly into the block property using an expression, use a dictionary type that is not read-only, such as Dictionary<TKey, TItem>.
When using a variable, convert the read-only dictionary to a dictionary that can be written to by using the .ToDictionary(item => item.Key, item => item.Value) expression like follows:
The exception thrown when trying to add an item to a dictionary with a key that is already present.
The format of the exception message is as follows:
"TODO.
Please click the HelpLink for more information on how to fix this."
How to fix
TODO:
6.5.4.4 - KeysNotPresentException
The exception thrown when trying to get items from a dictionary, or set items in a dictionary, and one of the keys used to find the items is not present.
The exception thrown when trying to get items from a dictionary, or set items in a dictionary, and one of the keys used to find the items is not present.
The format of the exception message is as follows:
"TODO.
Please click the HelpLink for more information on how to fix this."
How to fix
TODO:
6.5.4.5 - OccurrenceNotPresentException
The exception thrown when trying to get a specified occurrence of an item from a dictionary, or set a specified occurrence of an item in a dictionary.
"The connection attempt to 'Host' ('<host>') on 'Port' (<port>) failed. The 'Server Details' in 'Email Session Details' has been provided a port that does not exist or the connection timed out.
Please click the HelpLink for more information on how to fix this."
where:
<host> is the address of the mail server that a session is being opened with
<port> is the port on the mail server that a session is being opened with
How to Fix
Provide a valid Port between the Int32 values 1 and 65535 in the ServerDetails and ensure that the mail server is up and running without issues.
"Invalid 'Host' ('<host>') provided. The 'Server Details' in 'Email Session Details' has been provided a host that does not exist.
Please click the HelpLink for more information on how to fix this."
where:
<host> is the address of the mail server that a session is being opened with
A Category of SSL and an Error Code of 200 indicates that SSL is required. More specifically, the mail server is expecting that SSL is used as soon as the connection is established.
Message Format
"The connection could not be established or disconnected unexpectedly. Check if the 'Port' (<port>) provided requires that 'Use SSL' be set to true.
Please click the HelpLink for more information on how to fix this."
where:
<port> is the port on the mail server that a session is being opened with
A Category of SSL and an Error Code of 201 indicates that one of the following issues occurred:
An SSL connection is not supported. More specifically, the mail server either does not support SSL connections or only supports SSL connections via the STARTTLS command.
Certificate on the Host is expired, untrusted or invalid
Certificate replaced by anti-virus software in order to scan web traffic resulting in failed certificate validation
"The connection could not be established or disconnected unexpectedly. Check if the 'Port' (<port>) provided requires that 'Use SSL' be set to false. If this is not the case, check the inner exception.
Please click the HelpLink for more information on how to fix this."
where:
<port> is the port on the mail server that a session is being opened with
How to Fix
Change UseSsl in the ServerDetails to false, or make a connection on a port which supports SSL.
If the above suggestion does not fix the problem, check if the anti-virus software on the server executing the flow is replacing the SSL certificate in order to scan the web traffic, and change the settings appropriately if needed.
If the issue persists, please check the inner exception as instructed by the Message.
"The provided 'Username' and 'Password' is incorrect. The 'User Credentials' in 'Email Session Details' has been provided an incorrect username and password combination.
Please click the HelpLink for more information on how to fix this."
"The 'Certificate Path' ('<certificate-path>') or 'Certificate Password' is invalid. The 'Gmail OAuth Certificate Credentials' in 'Email Session Details' has been provided an incorrect certificate path or certificate password.
Please click the HelpLink for more information on how to fix this."
where:
<certificate-path> is the path pointing to the SSL certificate
"The 'From Address' ('<from-address>}') or 'Client Id' ('<client-id>') is invalid. The 'Gmail OAuth Certificate Credentials' in 'Email Session Details' has been provided an incorrect email address or Client ID.
Please click the HelpLink for more information on how to fix this."
where:
<from-address> is the email address to send the email from
<client-id> is the client ID for the client application
The error code for the exception, which is used to indicate the reason that the exception occurred, if there are multiple reasons that the exception can occur.
For EmailSessionException there are the following error codes:
The exception thrown when a file or folder operation failed for one or more paths.
Path Exceptions
PathDoesNotExist
The format of the exception message is as follows:
"TODO.
Please click the HelpLink for more information on how to fix this."
How to fix
TODO:
Blocks that can throw this exception
TODO:
PathTooLong
The format of the exception message is as follows:
"TODO.
Please click the HelpLink for more information on how to fix this."
How to fix
TODO:
Blocks that can throw this exception
TODO:
Indexes Of Duplicate Paths
/// If any path in the specified filePaths is duplicated and no exception is thrown for that path, the block will only process the first occurrence of the path, skipping any other occurrences.
/// If any path in the specified filePaths is duplicated and an exception occurs for that path an <see cref="OperationFailedException">OperationFailedException</see> will be thrown, and the path added to the "IndexesOfDuplicatePaths" dictionary in <see cref="OperationFailedException">OperationFailedException</see>.
Indexes Of Null Or Empty Paths
/// If any path in the specified filePaths is null or empty, an OperationFailedException will be thrown, and the path added to the “IndexesOfNullOrEmptyPaths” list in OperationFailedException.
How to fix
TODO:
6.5.7 - FlowException
The exception thrown by the ThrowNewFlowException block.
FlowException
(Cortex.Exceptions.FlowException)
The exception thrown by the ThrowNewFlowException block.
TODO:
How to fix
TODO:
6.5.8 - Flows
Exceptions related to Flows
6.5.8.1 - Blocks
Exceptions related to Blocks
6.5.8.1.1 - BlockTimeoutException
The exception thrown when a block timeout has been reached.
The exception message, providing information about the exception that occurred.
For this exception, the message will always be the same. More information on why the value is invalid, or instruction on how to provide a valid value, may be present in the message of the InnerException.
Currently, only the PropertyId has been included in the exception. In future, we will look to include the name and Id of the block, the name and value of the property, as well as allowing the exception to contain a link to take you directly to the offending value.
This exception is thrown when a flow is run and extra Input Variables have been provided; any extra variables will be shown in the InvalidVariableErrors property.
This exception is thrown when a flow is run and there are Input Variables that are of an invalid type; any variables with an invalid type will be shown in the InvalidVariableErrors property.
"Couldn't initialize variable store because of invalid input variables."
How to fix
Ensure the value provided for the variables referenced in InvalidVariableErrors is either the same type as, or can be implicitly cast to the type defined in the default value for that Input Variable.
Properties
Exception Type
The type of the exception (i.e. InvalidInputVariablesException).
The exception thrown when trying to modify a read-only list.
Lists deriving from IList<T> have the option to be read-only.
The format of the exception message is as follows:
"The value of '<property-display-name>' cannot be modified.
This is because the value of '<property-display-name>' is read-only.
See the CannotModifyReadOnlyListException help page for more information on how to fix this."
How to fix
If the list was written directly into the block property using an expression, use a list type that is not read-only, such as List<T>.
When using a variable, convert the list to a list that can be written to by using the .ToList() expression like follows:
($)List.ToList()
TODO: Confirm if this is all correct - look at cannotmodifyreadonlydictionaryexception for consistency
6.5.9.2 - DuplicateValueException
The exception thrown when a list contains duplicate values and shouldn’t.
DuplicateValueException
(Cortex.Exceptions.Lists.DuplicateValueException)
TODO: The exception thrown when…
The format of the exception message is as follows:
TODO:Format
How to fix
TODO: How to fix…
6.5.10 - Loops
Exceptions related to Loops.
6.5.10.1 - InfiniteLoopException
The exception thrown when an infinite loop can occur.
InfiniteLoopException
(Cortex.Exceptions.Loops.InfiniteLoopException)
Description
The exception thrown when an infinite loop can occur.
There are multiple reasons that this exception can be thrown:
A Category of "Increment"and an Error Code of 100 indicates that a zero increment value was provided.
Message Format
The format of the Message can be one of the following:
If a zero value was provided and a negative value was expected
"The 'Increment' provided (0) causes an infinite loop. It must be a negative value.
Please click the HelpLink for more information on how to fix this."
If a zero value was provided and a positive value was expected
"The 'Increment' provided (0) causes an infinite loop. It must be a positive value.
Please click the HelpLink for more information on how to fix this."
How to fix
Provide a negative or positive value for the increment as instructed by the Message.
Increment Is Negative
A Category of "Increment"and an Error Code of 101 indicates that a negative increment value was provided when a positive value was required.
"The 'Increment' provided ({NegativeIncrement}) causes an infinite loop. It must be a positive value.
Please click the HelpLink for more information on how to fix this."
How to fix
Provide a positive value for the increment as instructed by the Message.
Increment Is Positive
A Category of "Increment"and an Error Code of 102 indicates that a positive increment value was provided when a negative value was required.
"The 'Increment' provided ({PositiveIncrement}) causes an infinite loop. It must be a negative value.
Please click the HelpLink for more information on how to fix this."
How to fix
Provide a negative value for the increment as instructed by the Message.
Properties
Exception Type
The type of the exception (i.e. InfiniteLoopException).
The error code for the exception, which is used to indicate the reason that the exception occurred, if there are multiple reasons that the exception can occur.
For InfiniteLoopException there are three error codes:
100 - indicates the increment is zero, but should be either negative or positive
101 - indicates the increment is negative, but should be positive
102 - indicates the increment is positive, but should be negative
The exception thrown when a property is provided with an invalid regex value.
The format of the exception message is as follows:
TODO
How to fix
Provide a valid regex value for the property.
6.5.12 - Xml
Exceptions related to Xml blocks.
6.5.12.1 - XmlSerializationException
The exception thrown when an Xml Serialization errors occur.
XmlSerializationException
(Cortex.Exceptions.Xml.XmlSerializationException)
TODO: The exception thrown when…
The format of the exception message is as follows:
TODO:Format
How to fix
TODO: How to fix…
6.6 - Logs
This section includes all reference documentation for logs generated by the Cortex Innovation platform.
6.6.1 - Cortex Gateway
This section includes all reference documentation for the logs generated by Cortex Gateway.
6.6.2 - Cortex Studio
This section includes all reference documentation for the logs generated by Cortex Studio.
6.6.3 - Cortex Flow Debugger Service
This section includes all reference documentation for the logs generated by the Cortex Flow Debugger Service.
TODO:
Configuration
Serilog
Log Event block
Structure of a log
Different types of log
Pause
CreateDebugSession
etc
6.6.4 - Cortex API Gateway Service
This section includes all reference documentation for the logs generated by the Cortex API Gateway Service.
6.6.5 - Cortex Flow Execution Service
This section includes all reference documentation for the logs generated by the Cortex Flow Execution Service.
6.7 - Messages
This section includes all reference documentation for messages generated by the Cortex Innovation platform.
6.7.1 - Validation
This section includes all reference documentation for messages generated during validation.
6.7.1.1 - Errors
This section includes all reference documentation for errors generated during validation.
6.8 - Observability
This section includes all reference documentation for the Observability platform for Cortex Innovation.
6.8.1 - Grafana
This section includes all reference documentation for the Grafana Observability platform for Cortex Innovation.
6.8.1.1 - Dashboards
This section includes all reference documentation for the Cortex Innovation default set of Grafana dashboards.
6.8.1.1.1 - Flow Execution Requests
Information about the Flow Executions Request Dashboard.
Flow Execution Requests
Description
This dashboard provides the information required to analyse the flow execution requests within the Cortex Innovation platform. It will display data based on the Time Range that has been specified.
At the top of the page there is a dashboard description. This provides information about what the dashboard is reporting and what each of the filters are. The description is always collapsed by default.
There are several filters available to filter the data to a more fine-grained level as necessary and are explained in further detail below.
Time Range
Note
Choosing large time ranges will increase the time it takes for the data to be loaded into the dashboard.
The time range for which the dashboard displays data is configurable in the top right of the dashboard using the Time Range selector (defaults to the last 3 hours):
There are a number of predefined quick ranges to choose from:
Last 5, 15 and 30 minutes
Last 1, 3, 6, 12 and 24 hours
Last 2, 7, 30 and 90 days
Last 6 months
Last 1, 2 and 5 years
Yesterday
Day before yesterday
This day last week
Previous week, month, fiscal quarter, year, fiscal year
Today
Today so far
This month, fiscal quarter, year and fiscal year
This month, fiscal quarter, year and fiscal year so far
To configure an absolute time range, you should specify a From and To date and time. These values can be in the format of YYYY-MM-DD HH:MM:SS, e.g. 2022-07-22 13:54:23, or alternatively can use times relative to now, e.g. now-24h. It is also possible to use the date time picker available for both the From and To fields. Once the absolute time range has been configured you must click the ‘Apply time range’ button.
If an absolute time range is specified, the Time Range selector will show the selected time range with arrows either side. These arrows can be used to shift the time range forwards and backwards. This feature is not available for quick ranges.
The magnifying glass icon allows you to zoom out of the time range specified. It will substract half the current time range from the From field and add half the current time range to the To field.
For more information regarding the Time Range selector, see Grafana’s Time range controls documentation.
Filters
At the top of the dashboard, there are 10 filters available to restrict the data queried:
Filter
Description
Tenant
List of tenants. Defaulted to All.
System
List of systems. Defaulted to All.
Node
List of hosts that processed the requests. Defaulted to All.
Package Name
List of packages. Defaulted to All.
Flow Name
List of flows that have execution requests. Defaulted to All.
Status Code
List of status codes found in the HTTP responses. Defaulted to All.
Result
List of results found in the HTTP responses. Defaulted to All.
Initiator IP Address
List of IP addresses for the initiators of the requests. Defaulted to All.
Interval
List of intervals to perform the time series aggregations upon. This only affects the graphs on this dashboard.
The available values for this filter are auto, 1m, 10m, 30m, 1h, 6h, 12h, 1d, 7d, 14d, 30d.
If auto is selected, as is the default, Grafana will aggregate to a level it deems appropriate for the time range specified.
Custom Filter
Enables filtering on all available values, including those not exposed by default.
All filters (excluding Interval and Custom Filter) will display their list of available options dependent on the preceding filters selected.
Overview Section
This section displays key flow execution request metrics for the specified time range and consists of 4 panels.
Note
The Interval filter does not affect these panels.
Total Requests
This tile displays the total number of flow execution requests during the specified time range.
Total Requests Errored
This tile displays the total number of flow execution requests that errored during the specified time range. This tile has thresholds set to colour code the tile depending on the value. These thresholds can be customised, however the default thresholds are:
Threshold
Value
Colour
OK
0
green
CRITICAL
>= 1
red
Request Error Rate
This tile displays the percentage of errored flow execution requests against the total flow execution requests during the specified time range. This tile has thresholds set to colour code the tile depending on the value. These thresholds can be customised, however the default thresholds are:
Threshold
Value
Colour
OK
< 5%
green
WARNING
>= 5%
orange
CRITICAL
>= 10%
red
Mean Request Duration
This tile displays the mean duration for flow execution requests during the specified time range. This is usually reported in seconds, however the unit may change if the number is much smaller or larger.
Requests Section
This section provides information regarding the flow execution request history for the specified time range and consists of 3 panels.
Requests
This graph displays, for the specified time range, the:
count of all flow execution requests
mean duration in seconds for all flow execution requests
Each data point value is calculated by aggregating requests based on the Interval filter.
Top 10 Requests by Count
This table displays the 10 flows with the most execution requests during the specified time range with their mean, minimum and maximum duration in seconds.
Note
The Interval filter does not affect this table.
Bottom 10 Requests by Count
This table displays the 10 flows with the least execution requests during the specified time range with their mean, minimum and maximum duration in seconds.
Note
The Interval filter does not affect this table. Also, any flows with zero executions will not be displayed.
Errors Section
This section provides information regarding the errored flow execution request history for the specified time range and consists of 2 panels.
Errored Requests
This graph displays, for the specified time range, the:
count of errored flow execution requests
mean duration in seconds for errored flow execution requests
Each data point value is calculated by aggregating requests based on the Interval filter.
Top 10 Requests by Error Count
This table displays the 10 flows with the most errored execution requests (by status code and result) during the specified time range with their mean, minimum and maximum duration in seconds.
Note
The Interval filter does not affect this table.
Duration Section
This section provides information regarding the flow execution request duration history for the specified time range and consists of 3 panels.
Request Duration
This graph displays, for the specified time range, the:
mean duration in seconds for all flow execution requests
minimum duration in seconds for all flow execution requests
maximum duration in seconds for all flow execution requests
Each data point value is calculated by aggregating requests based on the Interval filter.
Top 10 Longest Running Requests by Mean Duration
This table displays the 10 flows whose execution requests have the longest mean duration during the specified time range with their total count, error count, minimum and maximum duration in seconds.
Note
The Interval filter does not affect this table.
Top 10 Shortest Running Requests by Mean Duration
This table displays the 10 flows whose execution requests have the shortest mean duration during the specified time range with their total count, error count, minimum and maximum duration in seconds.
Note
The Interval filter does not affect this table. Also, any flows with zero executions will not be displayed.
Remarks
Unknown values
The dashboard may display flow execution requests that have an Unknown status code or result, if they are missing from the raw logs. The chances of this occurring are minimal.
Known Limitations
Graphs do not reset to zero
There is a limitation in Grafana where the graph does not always return to the zero line when there is no data for a given time point. This only occurs when there is a data point available at the beginning of the graph, followed by a period with no data, then data occurs again. When hovering the mouse over this area, it will show that the value is 0, and any other tiles will reflect the zero data at this point accordingly.
Related Dashboards
None
6.8.1.1.2 - Platform Health
Information about the Platform Health Dashboard.
Platform Health
Description
This dashboard provides the information required to analyse the health of the Cortex Innovation platform. It will display data based on the Time Range that has been specified.
At the top of the page there is a dashboard description. This provides information about what the dashboard is reporting and what each of the filters are. The description is always collapsed by default.
There are several filters available to filter the data to a more fine-grained level as necessary and are explained in further detail below.
Time Range
Note
Choosing large time ranges will increase the time it takes for the data to be loaded into the dashboard.
The time range for which the dashboard displays data is configurable in the top right of the dashboard using the Time Range selector (defaults to the last 3 hours):
There are a number of predefined quick ranges to choose from:
Last 5, 15 and 30 minutes
Last 1, 3, 6, 12 and 24 hours
Last 2, 7, 30 and 90 days
Last 6 months
Last 1, 2 and 5 years
Yesterday
Day before yesterday
This day last week
Previous week, month, fiscal quarter, year, fiscal year
Today
Today so far
This month, fiscal quarter, year and fiscal year
This month, fiscal quarter, year and fiscal year so far
To configure an absolute time range, you should specify a From and To date and time. These values can be in the format of YYYY-MM-DD HH:MM:SS, e.g. 2022-07-22 13:54:23, or alternatively can use times relative to now, e.g. now-24h. It is also possible to use the date time picker available for both the From and To fields. Once the absolute time range has been configured you must click the ‘Apply time range’ button.
If an absolute time range is specified, the Time Range selector will show the selected time range with arrows either side. These arrows can be used to shift the time range forwards and backwards. This feature is not available for quick ranges.
The magnifying glass icon allows you to zoom out of the time range specified. It will substract half the current time range from the From field and add half the current time range to the To field.
For more information regarding the Time Range selector, see Grafana’s Time range controls documentation.
Filters
At the top of the dashboard, there are 9 filters available to restrict the data queried:
Filter
Description
Tenant
List of tenants. Defaulted to All.
System
List of systems. Defaulted to All.
Node
List of hosts that processed the requests. Defaulted to All.
API
List of the API endpoints found in the HTTP requests. Defaulted to All.
Status Code
List of status codes found in the HTTP responses. Defaulted to All.
Result
List of results found in the HTTP responses. Defaulted to All.
Initiator IP Address
List of IP addresses for the initiators of the requests. Defaulted to All.
Interval
List of intervals to perform the time series aggregations upon. This only affects the graphs on this dashboard.
The available values for this filter are auto, 1m, 10m, 30m, 1h, 6h, 12h, 1d, 7d, 14d, 30d.
If auto is selected, as is the default, Grafana will aggregate to a level it deems appropriate for the time range specified.
Custom Filter
Enables filtering on all available values, including those not exposed by default.
All filters (excluding Interval and Custom Filter) will display their list of available options dependent on the preceding filters selected.
Overview Section
This section displays key platform health metrics for the specified time range and consists of 4 panels.
Note
The Interval filter does not affect these panels.
Availability
This tile displays the availability of the platform by calculating the successful requests / total requests during the specified time range. Successful requests are all requests that do not result in a 5xx HTTP response, 4xx responses are considered successful in this scenario. This tile has thresholds set to colour code the tile depending on the value. These thresholds can be customised, however the default thresholds are:
Threshold
Value
Colour
OK
>= 95%
green
WARNING
>= 90%
orange
CRITICAL
< 90%
red
Total Requests
This tile displays the total number of requests during the specified time range.
Errored Requests
This tile displays the total number of errored requests during the specified time range. Errored requests are all requests that result in an unknown or 5xx HTTP response, 4xx responses are considered successful in this scenario. This tile has thresholds set to colour code the tile depending on the value. These thresholds can be customised, however the default thresholds are:
Threshold
Value
Colour
OK
0
green
CRITICAL
>= 1
red
Mean Request Duration
This tile displays the mean duration for requests during the specified time range.
Note
Certain APIs may take significantly longer than others skewing the result.
Availability Section
This section displays the availability of the Cortex Innovation platform and consists of 1 panel.
Availability
This graph displays the availability of the Cortex Innovation Platform during the specified time range by calculating successful requests / total requests. Successful requests are all requests that do not result in an unknown or 5xx HTTP response. 4xx responses are considered successful in this scenario.
Each data point value is calculated by aggregating requests based on the Interval filter. If there is no data for the previous interval, the line will be broken as the availability is not known at the time.
This graph has thresholds set to colour code the background to show when availability drops into warning and critical levels. These thresholds can be customised, however the default thresholds are:
Threshold
Value
Colour
OK
>= 95%
green
WARNING
>= 90%
orange
CRITICAL
< 90%
red
This graph is configured to start the availability axis at 80%. However, if the availability drops below this level, the axis will modify to show the lowest availability level.
Requests Section
This section provides information regarding the history of the requests processed by the Cortex Innovation platform for the specified time range and consists of 2 panels.
Requests
This graph displays, for the specified time range, the:
count of all requests. Each data point value is calculated by aggregating requests based on the Interval filter.
count of all requests per second.
Top 10 Responses by Total Count
This table displays the Top 10 HTTP responses that occurred during the specified time range with their mean, minimum and maximum duration in seconds.
Note
The Interval filter does not affect this table.
Errors Section
This section provides information regarding the errored request history for the specified time range and consists of 2 panels.
Errored Requests
This graph displays, for the specified time range, the:
count of errored requests
count of all requests
Each data point value is calculated by aggregating requests based on the Interval filter.
Errored requests are all requests that result in an unknown or 5xx HTTP response. 4xx responses are considered successful in this scenario.
Top 10 Error Responses by Error Count
This table displays the Top 10 HTTP error responses that occured during the specified time range with their mean, minimum and maximum duration in seconds. Errored requests are all requests that result in an unknown or 5xx HTTP response. 4xx responses are considered successful in this scenario.
Note
The Interval filter does not affect this table.
Duration Section
This section provides information regarding the request duration history for the specified time range and consists of 2 panels.
Note
Certain APIs may take significantly longer than others skewing the result.
Request Duration
This graph displays, for the specified time range, the:
mean duration in seconds for all requests
minimum duration in seconds for all requests
maximum duration in seconds for all requests
Each data point value is calculated by aggregating requests based on the Interval filter.
Top 10 Responses by Mean Duration
This table displays the top 10 HTTP responses that occurred during the specified time range with their mean, minimum and maximum duration in seconds.
Note
The Interval filter does not affect this table.
Remarks
Unknown values
The dashboard may display HTTP requests that have an Unknown status code or result, if they are missing from the raw logs. The chances of this occurring are minimal.
Breaks in Graph Lines
When appropriate, there may occur breaks in the line graphs. This is relevant to the Availability graph. When there is no data, it is not appropriate to say that the availability is the same as the previous data point or that it is zero as if there is no data, we cannot accurately reflect the data at this point, and therefore, the line will break.
Known Limitations
Graphs do not reset to zero
There is a limitation in Grafana where the graph does not always return to the zero line when there is no data for a given time point. This only occurs when there is a data point available at the beginning of the graph, followed by a period with no data, then data occurs again. When hovering the mouse over this area, it will show that the value is 0, and any other tiles will reflect the zero data at this point accordingly.
Related Dashboards
None
6.8.1.2 - Advanced Setup
This section includes supporting documentation for the Grafana Observability platform.
6.8.1.2.1 - Configuring Thresholds
Instructions on how to configure thresholds in the Grafana Dashboard panels.
Configuring Thresholds
Configure Thresholds
This section explains how to change the colour coding of thresholds set for the thresholded panels in the dashboards.
Log in to your configured Grafana with a user that has the Admin role.
To open a dashboard:
Click the Dashboards icon in the side menu, and then click Browse.
Click the folder name that the dashboards were imported to.
Click the name of the dashboard you wish to modify to open it.
Open the panel you wish to configure in edit mode:
Click the title of the panel to display a drop-down menu.
Click Edit.
On the Edit Panel page, on the right-hand side, scroll down through the list of options until you reach the Thresholds section.
You can change the value configured for the colours defined if the thresholds should be different to the default set for that panel.
You can change the colours defined for the thresholds to be different to the default set for that panel.
You can add additional threshold levels by clicking + add threshold and configuring the colours and numbers appropriately. E.g. on the Total Requests Errored panel on the Flow Execution Requests dashboard, you may wish to add a warning threshold level to be >= 1 errors and change the critical threshold to be >= 10. For this you should add a threshold and set the colour to your preferred colour, set the value to 1 and change the value for red to be 10.
The threshold should be set to be an absolute value if it is a count e.g. error count, or a percentage if it is a rate e.g. success rate.
Click Apply in the top right corner of the Edit Panel page.
Save the changes to the dashboard by clicking on the save (disk) icon, in the top right of the dashboard.
6.9 - Troubleshooting
This section includes information about how to troubleshoot the platform.
6.9.1 - Installation
Information on troubleshooting Cortex Innovation installations.
Installation
Troubleshooting issues during installation
Root certificate verification failed as no root certificate has been specified
If the installation fails with Root certificate verification failed as no root certificate has been specified. it means that Windows has not got the trusted root installed for the provided X.509 certificate. This can be rectified by providing the path to a .pem file containing the root certificate in the pemRootCertificatePath property for each certificate in the serverCertificates and/or adminCertificates section of the configuration file. After adding this, the installation script can be re-run. The following steps can be taken to create a .pem file and re-run the installation (these instructions may differ slightly depending on the Certificate Authority):
In order to find out the issuer of the certificate, if not already known, the following script can be used, replacing the password for the pfx file and certificate path as necessary:
This will give a list of Other Certificates and End Certificates contained in the .pfx file. The issuer can be found in the Issuer property of one of the Other Certificates. If there are more than one, it will be the one that does not appear as a Subject in any of the other items.
E.g. For a “Let’s Encrypt” certificate this will give the following results:
In this case, the root certificate is DST Root CA X3.
In a search engine, search for the CN of the issuer and one of the results should lead to a download of a .pem file or to a page with the certificate on it, which can then be copied and saved into a file with a .pem extension. Often, searching the issuer of the EndEntityCertificate, in the above case Let’s Encrypt, will also work.
E.g. for Let’s Encrypt, the results of the search for DST Root CA X3 leads to https://www.identrust.com/dst-root-ca-x3 which provides the following text to be saved as a .pem file:
If a load balancer is being used (not single server), modify the installation configuration file to include the .pem file as the pemRootCertificatePath in the adminCertificates like so:
It means there is probably something wrong with the certificate verification with RabbitMQ. Please report issues like this to Cortex Service Portal.
To work around this error, either uninstall the platform and reinstall it using a different certificate, otherwise disable peer-to-peer verification in RabbitMQ by carrying out the following steps:
Uninstall the platform by taking the following steps:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Uninstall the platform by running the following command for your architecture:
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all servers (Application and Load Balancer) and press OK.
Wait for the command to finish.
In the Cortex Innovation 2022.9 - App Server Install Scripts folder, navigate to Resources.
Backup the file RabbitMqInterNodePublicTemplate.config and then open it with a text editor.
Replace both instances of the text verify_peer with the text verify_none.
Change the value of both occurrences of fail_if_no_peer_cert to false so that they resemble the following:
{fail_if_no_peer_cert, false},
Save and close RabbitMqInterNodePublicTemplate.config.
Re-run the installation script.
Troubleshooting issues after installation
Cortex Innovation features not visible in Cortex Gateway
Check that the Feature Flags Guid in the CortexGateway.SetParameters.xml file used for installing Cortex Gateway is correct. If it is not, update it and reinstall Cortex Gateway or update the value in the web.config file and restart the website. If the value is correct, please contact Cortex Service Portal for assistance.
Cortex Innovation blocks not visible in Cortex Studio
Check that the Dot NET flow debugger Endpoint URL in the CortexGateway.SetParameters.xml file used for installing Cortex Gateway is correct pay particular attention to the protocol - it should usually be https. If it is not, update it and reinstall Cortex Gateway or update the value in the web.config file and restart the website.
Ensure that the Flow Debugger Service is running. Open IIS, click on Application Poolsand ensure there is a debugger application pool which is showing that it is associated with 1 application. If not, go back to the Cortex Flow Debugger Service installation steps and ensure that all steps were followed correctly.
If no misconfiguration can be found, the service log files may contain more information. These can be found on the Web Application Server at:
%ProgramData%\Cortex\Cortex Flow Debugger
C:\temp\Cortex.Gateway.log
Restart the Cortex website. Open IIS, In the Connection pane, browse to Sites. Select the Cortex website and click Restart in the Manage Website pane.
If the issues cannot be resolved, please contact Cortex Service Portal for assistance.
Cannot publish a package
Check that the Service Fabric Api Gateway Endpoint, Service Fabric Using Self Signed Certificates, Service Fabric ApiGateway Basic Auth Username and Service Fabric ApiGateway Basic Auth Password in the CortexGateway.SetParameters.xml file used for installing Cortex Gateway are correct. If any of them are not, update them and reinstall Cortex Gateway or update the value in the “web.config” file and restart the website. If the value is correct, please contact Cortex Service Portal for assistance.
Ensure that the Application Services are healthy by following these steps:
Log on to one of the Application Servers and open a web browser.
Navigate to https://app-server.domain.com:9080/Explorer, where app-server.domain.com is the fully qualified domain name of any Application Server. Replace 9080 with new httpGatewayEndpointPort value if it was changed during configuration.
If page access is denied it may be necessary to import the server certificate used in installation to the Current User certificate store (usually achieved by double clicking on it and following the wizard). If using self-signed certificates, the certificate can be retrieved by using the Manage Computer Certificates tool in Windows to export the CortexServerCertificate from the Personal store and then importing it to the Current User store by double-clicking on it and following the wizard. The browser may need to be restarted before the site can be accessed
The screen should resemble that in the following figure, all services should have Health State = OK and Status = Active. All instances below the service should have Health State = OK and Status = Ready.
Healthy Service Fabric Explorer
If any warning triangles appear, wait for 5 minutes or so as the cluster may still be starting up. If the cluster looks OK, ignore the rest of this step. If the warnings persist or anything on the screen goes red, use the filter buttons to find the individual elements which have errors or warnings. Warnings should not be ignored as they can indicate that the service can’t start but is still in the retry phase.
If no useful message can be seen here, the service log files may contain more information.
There may be times when the logs provided by the Cortex Services and the errors displayed in Service Fabric Explorer are not enough to debug an issue that is occurring on the system. This can be due to RabbitMQ being a state where it can’t send messages between services.
To check that RabbitMQ is working as expected, remote desktop to an Application Server and navigate to https://app-server1.domain.com:15671, replacing app-server1.domain.com with the FQDN of one of the Application Servers. Sign in with username ‘administrator’ and the RabbitMQ password provided during the Application Server installation. The following should be displayed in the overview tab for a healthy cluster:
Healthy RabbitMQ status.
Note
The username and password are not secure, but the RabbitMQ manager will only allow you to connect from localhost so it is not accessible to anyone who does not have remote desktop access.
If there are any unhealthy nodes (red) you may need to restart the RabbitMQ Windows service on each of the nodes that is erroring. These can be restarted in any order, but they must be restarted one at a time; wait for the node in the RabbitMQ explorer to be green before restarting the next one (you may need to refresh the browser).
Service Fabric Explorer displays errored services with RabbitMQ Broker Unreachable Exceptions
If, when checking Service Fabric Explorer, all services are showing as erroring and the details are displaying a message similar to the following:
RabbitMQ.Client.Exceptions.BrokerUnreachableException (-2146232800)
None of the specified endpoints were reachable
There may be due to an incompatibility between the version of OpenSSL used and your processor. From Intel’s website: “OpenSSL 1.0.2 beta (Jun 2014) to OpenSSL 1.0.2k (Jan 2017) contain bugs that either cause a crash or bad SHA (Secure Hash Algorithm) values on processors with the SHA extensions. Both bugs were fixed years ago; however, any application that uses the old version directly, or as one of its dependencies, will fail”*
To verify that this is the problem, open Event Viewer and look in Windows -> Application. If this problem has occurred there will be some errors in the event viewer which contain the following:
Faulting application name: erl.exe, version: 0.0.0.0, time stamp: 0x5d80b978
Faulting module name: crypto.dll, version: 0.0.0.0, time stamp: 0x5d80baab
A workaround for this is provided by Intel.
Uninstall the platform by taking the following steps:
Open a Windows PowerShell (x64) window as administrator.
Navigate PowerShell to inside the Cortex Innovation 2022.9 - App Server Install Scripts folder using the following command, modifying the path as necessary:
cd "C:\Install\Cortex Innovation 2022.9 - App Server Install Scripts"
Uninstall the platform by running the following command for your architecture:
A credentials prompt will appear. Enter credentials of a domain user that is a member of the local Administrators group on all servers (Application and Load Balancer) and press OK.
Wait for the command to finish.
Add a system environment variable, provided by Intel, to each Application Server by taking the following steps:
Remote desktop to one of the Application Servers.
Right-click on the Start Menu and select System.
Click Advanced system settings to open the System Properties dialog.
Click Environment Variables....
Under System variables, click New... to open the New System Variable dialog.
Set the Variable name to OPENSSL_ia32cap and the Variable value to :~0x20000000. Make sure to include the colon at the start.
Click OK.
Repeat these steps for any other Application Servers.
Run the Application Servers installation script again.
Service Fabric Explorer displays certificate is about to expire warning
If Service Fabric certificates are going to expire in fewer than 30 days, a warning is displayed as follows:
Service Fabric Explorer Certificate Expiring
Certificate expiration: thumbprint = {thumbprint}, expiration {date} remaining lifetime is {time} please refresh ahead of time to avoid catastrophic failure.
If this occurs on your server it is important to update your certificates as soon as possible using Rollover Certificates.
6.10 - Glossary
Explanation of terms, words and phrases used throughout the Cortex documentation.
6.10.1 - A-E
Terms, words and phrases beginning with the letters A through E.
A-E
Terms, words and phrases beginning with the letters A through E.
An API (Application Programming Interface) is a set of functions that allows applications to access data from and interact with external systems, services or applications.
Autogeneration
Autogeneration, is the process in which something is created automatically for use within a process.
Automation is a term for techniques, methods, systems or technologies that reduce human intervention in tasks and processes.
AWS Lambda
AWS Lambda is an event driven serverless solution from AWS. Instead of deploying and maintaining servers, cloud infrastructure is used to run applications.
Azure Functions
Azure Functions is an event driven serverless solution from Microsoft. Instead of deploying and maintaining servers, cloud infrastructure is used to run applications.
B
BCC
Blind Carbon Copy (BCC) is a way of sending copies of an email to other people. Unlike CC recipients, the other recipients of the email will not be able to see who recieved the email via BCC.
Bit
A bit is the most basic unit of information in computing, and represents a logical state with one of two possible values; most commonly represented as 1 or 0.
Blocks have block properties (or properties) that allow the flow developers to configure how the block should behave; e.g. a block to send emails would have properties for specifying things like the sender, recipients, summary, body, attachments etc.
It is natively supported by the Cortexplatform for using simple expressions (i.e. 1 + 1) and more complex code (i.e. DateTime.Now.AddDays(1)) within flows.
See the official C# documentation for more information about C#.
camelCase
camelCase is a typographical convention in which phrases are written without spaces or punctuation, indicating the separation of words with a single capitalized letter, and the first word starting with a lowercase letter. E.g. “iPhone” and “eBay”.
camelCase is often used as a naming convention in programming languages such as C#.
Carbon Copy (CC) is a way of sending copies of an email to other people. The other recipients of the email will be able to see who recieved the email via CC.
CI/CD
CI/CD is a software development practice and is broken down into the following concepts:
A data type that represents a character or letter.
For more detailed information about the Char data type, see Data Types > Char.
Cloud
A global network of servers which are linked together and operate as a single ecosystem.
Examples of publicly available Cloud providers include:
Amazon AWS
Google Cloud Platform
Microsoft Azure
Cloud Service Provider
A cloud service provider is a third-party company offering a cloud-based platform, infrastructure, application, or storage services.
Code
A set of instructions in a computer program.
Concurrent
At the same time.
Continuous Integration
Continuous Integration is a software development practice where developers frequently:
Integrate their local changes with source code from the main branch
Use automated testing to ensure that their changes work as expected
Merge their changes into the main branch, if no issues were found
Continuous Delivery
Continuous Delivery is a software development practice where:
Changes to the main branch are detected
The main branch is packaged into deployment artefacts
Deployment artefacts are made available
Continuous Deployment
Continuous Deployment is a software development practice which extends Continuous Delivery by automatically deploying the generated artefacts.
Convert
To change something into a different form. E.g. Change some text from lowercase to UPPERCASE.
Cortex
The name of the new and current generation of the Cortex automationplatform.
Cortex Gateway
The centralised web-based portal for accessing all user applications and tooling in the Cortexplatform.
Cortex Studio
The web-based integrated development environment (IDE) for creating, editing, debugging, testing and managing flows that define the logic and actions required to capture and automate a task or process.
Describes a set of rules for data that differs between different cultures; it determines the default format for dates, times, numbers, currency values, the sorting order of text, casing conventions, and text comparisons.
A culture identifier is a standard international numeric abbreviation and has the components necessary to uniquely identify one of the operating system’s installed cultures.
If something is culture-insensitive, it means that it does not get affected by culture related changes to the operating system, such as language and regional settings.
Culture-sensitive
If something is culture-sensitive, it means that it does get affected by culture related changes to the operating system, such as language and regional settings.
Current Culture
The current culture used by the executing thread; it determines the default format for dates, times, numbers, currency values, the sorting order of text, casing conventions, and string comparisons.
Certificate Revocation List (CRL) is a list of certificates that have been revoked by the issuing certificate authority prior to their actual/assigned expiration date. It is essentially a list of certificates that should no longer be trusted.
D
Data Type
A data type (or type) defines the type of data or values that a block property can accept.
The ability for flow developers to execute and interact with a flow step-by-step from within Cortex Studio, so that they are able to identify and remove errors in the flow’s logic and actions.
A developer is an individual that builds and creates software and applications.
Dictionary
A data type that represents an unordered collection of key-item pairs, where each pair consists of a unique key and its associated item. Dictionaries are optimised for fast lookup of items using their key.
DLL files are binary files that can contain executable code and resources.
Drag-and-Drop
Functionality that allows a user to select an object and move it to another location.
Double
A data type that represents a fractional, or very large or small number from -1.79769313486232e+308 through 1.79769313486232e+308.
For more detailed information about the Double data type, see Data Types > Double.
dynamic
A data type that indicates that any data type can be used.
For more detailed information about the dynamic data type, see Data Types > dynamic.
E
Empty
Empty indicates that a data type has been initialised and has a non-null value, but the value does not contain any data. E.g. a string that contains no characters "", or a list that contains no items [].
Exceptions are data types that can be reasoned with during the execution of a flow, in order to handle errors during the automation of a task or process.
Sometimes, in order to convert one data type to another, an “explicit cast” expression is required; this is typically needed when information might be lost in the conversion, or when the conversion might not succeed for other reasons.
Terms, words and phrases beginning with the letters F through J.
F-J
Terms, words and phrases beginning with the letters F through J.
F
File
A file is an object on a computer that stores data.
Different files can store different types of data (i.e. a text file, .txt, stores textual data; an executable file, .exe stores data required for executing an application).
Generic means not specific to a particular data type.
An example of a generic data type is List<TItem> where TItem is a placeholder which indicates it can be initialised with any data type, such as:
List<int> and List<string> which are homogenous lists that can only contain integers and strings respectively
List<object> and List<dynamic> are heterogenous lists that can contain multiple data types
Gmail
Gmail is a free web-based email service provided by Google.
GUI
GUI stands for “Graphical User Interface”. It is used to graphically display information and represent user interactions with a system, without the need for typing commands.
Some common and popular examples of IDE’s include:
Visual Studio
VSCode
Eclipse
IMAP
Internet Messaging Access Protocol (IMAP) in an internet protocol used by email clients to retrieve email messages from a mail server.
Immutable
Unable to be changed.
Implicit Cast
The process of an application converting one data type to another, without requiring an explicit instruction from the developer.
For one data type to be able to be implicitly cast to another, there should be no data loss during the conversion.
An example would be converting a 16-Bitinteger (Int16) to a 32-Bitinteger (Int32), as the entire range of the 16-bit integer will fit into a 32-bit integer:
See Explicit Cast for an example of where data loss would occur during conversion, and would therefore require an explicit instruction from the developer.
InputOutput properties are used to provide values to a block. These properties are used, updated and saved back to a variable during the block’s execution.
A data type that represents a whole number from -32,768 through 32,767.
For more detailed information about the Int16 data type, see Int16.
Int32
A data type that represents a whole number from -2,147,483,648 through 2,147,483,647.
For more detailed information about the Int32 data type, see Int32.
Int64
A data type that represents a whole number from -9,223,372,036,854,775,808 through 9,223,372,036,854,775,807.
For more detailed information about the Int64 data type, see Int64.
Invariant Culture
A culture associated with the English language, but not with any country or region; it determines the default format for dates, times, numbers, currency values, the sorting order of text, casing conventions, and string comparisons.
It has a stable and unchanging set of rules that cannot be customized and is unaffected by culture related changes to the operating system.
A data type that indicates that any data type can be used.
For more detailed information about the Object data type, see Data Types > Object.
Occurrence
A value can occur in a collection multiple times, these are called Occurrences.
Occurrences are 1 based (e.g. The first occurrence of an item in a list is at occurrence 1, the second occurrence of an item is at occurrence 2, etc.).
On-premise refers to infrastructure and software that is deployed and running within a physical location of an organisation.
Operand
Describes a literal or variable that has the capability to be operated on. For example, in the expression1 + 2 the literal values 1 and 2 are operands, whereas + is an operator.
Operator
Operators are used to manipulate and check operands values. For example, in the expression1 + 2 the operator + adds the two operands1 and 2, resulting in the expression evaluating to 3.
Out-of-the-box functionality of a product that works immediately after any installation without any configuration or modification.
Outlook
Outlook is a free web-based email service provided by Microsoft.
6.10.4 - P-T
Terms, words and phrases beginning with the letters P through T.
P-T
Terms, words and phrases beginning with the letters P through T.
P
PascalCase
PascalCase is a typographical convention in which phrases are written without spaces or punctuation, indicating the separation of words with a single capitalized letter, and the first word also starting with a capitalized letter. E.g. “FirstName” and “LastName”.
PascalCase is often used as a naming convention in programming languages such as C#.
In C#, a Property is used to access or update attributes of a data type (e.g. the Message property of an Exception returns the reason the exception occurred).
For more detailed information about the String data type, see Data Types > String.
Structure
A data type that represents a collection of key/item pairs, where each pair consists of a unique String key and its associated item.
For more detailed information about the Structure data type, see Data Types > Structure.
Syntax Highlighting
Syntax highlighting is a feature of text editors that are used for programming. The feature displays text in different colours and fonts according to a category of terms.
Syntax Highlighting improves the readability and provides context of text, and can be used to identify errors within a block of code.
T
Task
A unit of work to be done or undertaken.
Text
Data which can be interpreted as human-readable text, this is represented by Strings in C#.
Title Case
Title Case is a typographical convention in which the first letter of all words are capitalized and all other letters lower cased; except for words that are entirely upper cased, such as acronyms, which remain upper cased.
TLS
Transport Layer Security is a more secure, updated version of SSL. Note that TLS is still often referred to as SSL.
Trigger
A mechanism used to initiate an action when a specific event occurs (e.g. When a given date or time is reached).
In programming, whitespace is any character or series of characters that represent horizontal or vertical space in typography. When rendered, a whitespace character does not correspond to a visible character, but typically does occupy an area on a page.
PowerShell is a task automation and configuration management program from Microsoft, consisting of a command-line shell and the associated scripting language.
See What is PowerShell? for more information about PowerShell Core and Windows PowerShell.
X
Y
Z
Zero Based
Zero Based is a way of numbering in which the initial item of a list is assigned the index0.
6.10.6 - 0-9
Terms, words and phrases beginning with the numbers 0 through 9.
0-9
Terms, words and phrases beginning with the numbers 0 through 9.